luogu p5677 配對統計

2022-09-26 09:15:12 字數 2745 閱讀 3576

傳送門給定乙個序列 \(a\) ,定義 \((x, y)\) 為好的配對當且僅當 \(1\le x, y \le n, x \ne y\) 且對於 \(\forall i \in \\) 有 \(|a_x - a_y| \le |a_x - a_i|\)。給定 \(m\) 組詢問,每組詢問給定 \(l, r\)(\(1 \le l \le r \le n\)),查詢 \([ l, r]\) 中有多少好的配對。

首先可以觀察到,題目對於好的配對的描述其實就是說 \(a_y\) 對於 \(a_x\) 而言是整個數列中差最小的。很自然想到排序,排序後好的配對一定會相鄰。需要注意的是,排序時應該採用結構體,才能保護好數列中每乙個數的位置資訊。其次注意原題的資料已經給出了每個數不同的限定。

排序後,設排序後的下標是 \(i\),排序前的位置是 \(pos_i\),對於每個數進行判斷:

需要注意的是,對於好的配對 \((x, y)\),\((y, x)\) 不一定是好的配對!比如 \(3, 1, 4\),\((2, 1)\) 就是好的配對,而 \((1, 2)\) 不是。但是在這裡,如果好的配對 \((x, y)\) 有 \(x > y\),那麼我們將 \(x, y\) 進行調換,以 \((y, x)\) 的形式記錄為好的配對。雖然 \((y, x)\) 本質上並不是好的配對,但這種記錄方式完全不會影響答案。非得這麼記錄也不是吃飽了撐的,這是便於後面的處理,請接著往下看。

上面我們已經處理好了好的配對資訊,那麼接下來進入第二部分,統計好的配對。

首先我們會發現,直接將所有好的配對統計進去很難用樹狀陣列處理。又觀察到題目中所給的操作只有查詢,沒有增刪改。不免想到hh的項鍊,一切似乎都告訴我們,正解應該是將查詢離線。

先考慮將查詢按照r第一關鍵字l第二關鍵字從小到大排序,這樣,每次查詢都相當於查詢右邊界r在不斷向右挪動。

不妨假想乙個陣列 \(b_i\) 表示左端點 \(l \le i\) 的好的配對個數。每次掃到乙個詢問,首先把右邊界向右挪動到當前詢問的右邊界,挪動的過程中可能會掃過一些好的配對的右邊界,此時我們考慮將這樣的好的配對統計起來,再減去 \(b_\),也就是扣除左邊界在要查詢左邊界之外的不符合條件的好的配對。

所以還需要提前將好對也按照右邊界第一左邊界第二排一下序……

下面是來自zhr的部落格的圖例

實線就是當前選中的好的配對,虛線就是未選中的好的配對。\(q_4 和 q_5\) 未被選中的原因是仍未掃到,而 \(q_3\) 則是因為其左邊界超過了當前查詢的左邊界(包含在 \(b_\) 中)。

\(b\) 陣列怎麼維護呢?想必聰明的你已經想到,用樹狀陣列簡單維護一下即可

處理好的配對時間複雜度 \(\mathcal(n\log n)\)。(排序 \(\mathcal(n\log n)\),預處理好對 \(\mathcal(n)\))

統計好的配對時間複雜度 \(\mathcal((m+n)\log n)\)。(\(\log n\) 在樹狀陣列上)

/*

* @author: crab-in-the-northeast

* @date: 2022-02-27 20:49:14

* @last modified by: crab-in-the-northeast

* @last modified time: 2022-02-27 22:25:20

*/#include #include #include #define int long long

inline int read()

while (ch >= '0' && ch <= '9')

if (flag)

return x;

return ~(x - 1);

}const int maxn = 300005;

const int maxm = 300005;

int n, m;

inline int lowbit(int x)

struct number

}a[maxn];

struct pair

}p[maxn * 2];

int pcnt;

inline void insert_pair(int l, int r)

struct question

}q[maxm];

int c[maxn];

void add(int x)

int query(int x)

signed main()

for (int i = 1; i <= n; ++i)

std :: sort(a + 1, a + 1 + n);

insert_pair(1, 2);

insert_pair(n - 1, n);

for (int i = 2; i < n; ++i)

std :: sort(p + 1, p + 1 + pcnt);

for (int i = 1; i <= m; ++i)

std :: sort(q + 1, q + 1 + m);

int ans = 0;

for (int i = 1, j = 1; i <= m; ++i)

printf("%lld\n", ans);

return 0;

}

本題最大亮點離線。

Luogu P1110報表統計(Splay)

題目鏈結 sbt,我居然沒看出來。就是插入的時候考慮向平衡樹里插兩個差值,刪乙個差值。另乙個操作就是維護某元素和其前驅後繼的差值最小值就行了。然後splay超時了 貌似splay超時了之後我都是修改splay操作的頻率暴力硬卡,而不是考慮換一種思路 然後就被我卡過了。luogu judger ena...

luogu P1026 統計單詞個數

題目描述 給出乙個長度不超過 200 的由小寫英文本母組成的字母串 該字串以每行 20 個字母的方式輸入,且保證每行一定為 20 個 要求將此字母串分成 k 份,且每份中包含的單詞個數加起來總數最大。每份中包含的單詞可以部分重疊。當選用乙個單詞之後,其第乙個字母不能再用。例如字串 this 中可包含...

GZOI 2017配對統計 樹狀陣列

最開始讀題的時候沒有讀的太懂,以為i是在選定區間內給的,實際上不是,這道題的意思應該是在l和r的區間內找出有多少個好的配對,這裡好的配對是對於整個區間來說的,既然是對於整個區間,我們就不難想到找出好的配對的方法,所以我們可以先找出所有好的配對,然後用樹狀陣列維護個數。如何找出好的配對呢?我們先來分析...