傳送門給定乙個序列 \(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的區間內找出有多少個好的配對,這裡好的配對是對於整個區間來說的,既然是對於整個區間,我們就不難想到找出好的配對的方法,所以我們可以先找出所有好的配對,然後用樹狀陣列維護個數。如何找出好的配對呢?我們先來分析...