這道題是zyd在濟南三期qbxt講bitset的時候提到的,不過我好像當時秒了正解的樣子。。。\(*************************==分割線******************************==\)
其實cdq分治的思想與應用都能被很簡單地描述——它是用來解決各種區間段轉移問題\(x -> y (x < y)\)的一種演算法。
我們用f[x]表示位置x轉移之後的結果,用solve(l,r)來傳遞完全限制在[l,r]範圍內的狀態轉移,並且轉移\(a->b\)一定有\(a
那麼對於solve(l,r)
1.可以把這些問題排成乙個序列,用乙個區間[l,r]表示。這樣cdq分治就做完啦2.分。遞迴處理左邊區間[l,m]和右邊區間[m+1,r]的問題。
3.治。合併兩個子問題,同時考慮到[l,m]內的修改對[m+1,r]內的查詢產生的影響。即,用左邊的子問題幫助解決右邊的子問題
那cdq有什麼好處呢?
cdq分治是我們處理各類問題的重要**我們考慮一下,這道題的要求是求三維偏序,但是好像cdq分治只能求二維偏序的樣子qwq。。。它的優勢在於可以頂替複雜的高階資料結構,而且常數比較小;
缺點在於必須離線操作。
所以我們先在cdq分治之前,把其中1維變成有序的,然後再分治下去,這時在區間\([l,mid]\)關於區間\([mid + 1,r]\)就不存在某一維的逆序了,所以就只剩下2維,於是就將三維偏序成功的轉化為可以用cdq分治來解的二維偏序問題。
這個時候來一波樹狀陣列求逆序對的操作搞一下二維偏序,就可以把跨過中線的,左邊更新右邊的情況計算出來,然後左右兩邊遞迴處理就好了。。。
注意:只計算左邊的操作對右邊的詢問的貢獻!!!
時間複雜度 : 分治 + 樹狀陣列 = \(o(nlog^2 n)\)
#include#include#include#include#includeusing namespace std;
const int n = 200100;
struct qaq
inline bool operator < (const qaq &b) const
}a[n],c[n];
int m,n,ans[n],opt[n];
inline int lowbit(int x)
inline bool cmp(qaq a,qaq b)
void print(int x,int y)
}int gets(int x)
return sum;
}void clean(int x)
}void cdq(int l,int r)
a[j].p += gets(a[j].z);
} for(int i = l ; i <= mid ; i++) clean(a[i].z);
for(int i = l ; i <= r; i++) c[i] = a[i];
i = l; int j = mid+1;
for(int k = l ; k <= r ; k++) else a[k] = c[j++]; }}
int main()
sort(a+1,a+n+1,cmp);
cdq(1,n);
sort(a+1,a+n+1,cmp);
int i = 1;
while(i <= n)
for(int i = 0 ; i < n ; i++)
printf("%d\n",ans[i]);
return 0;
}
三維偏序(陌上花開)
這是一道模板題 可以使用bitset,cdq分治,k dtree等方式解決。有 n個元素,第 i個元素有 ai bi ci 三個屬性,設 f i 表示滿足 aj ai 且 bj bi 且 cj ci 的 j 的數量。對於 d 0,n 求 f i d 的數量 輸入格式 第一行兩個整數 n k,分別表示...
三維偏序 陌上花開
有 n 個元素,每個元素有三個屬性 a i b i c i 定義 f i 為滿足 a j a i 且 b j b i 且 c j c i 的 j 的個數 ans i sum f j i 求所有的 ans i 陌上花開,心憂梓桑。cdq 分治模板題 首先以 a 為關鍵字排序,省略一維 再以 b 為關鍵...
陌上花開(三維偏序)(cdq分治)
其實就是三位偏序的模板,cdq分治入門題。學習cdq分治請看 stdcall大佬的部落格 傳送門 排序來維護第一層,cdq維護一層,樹狀陣列維護一層,然後就沒有啦qwqwq include include include include include define maxn 100010 usin...