四维偏序 CDQ套CDQ
對CDQ深一步的理解
昨天做了一道CDQ,看了一堆CDQ可做的題,今天又做了一道四維偏序
感覺對CDQ的理解又深了一點,故來寫一寫現在自己對于CDQ的理解
CDQ其實就是實現了這樣的一個問題的轉化:
\(a_{l} < a_{l+1} < ... < a_r => (a_l,a_{l+1},...,a_{mid}) \text{都小于} (a_{mid+1},a{mid+2},...,a_r)\)
然后我們就知道這時候左邊所有的點都一定小于右邊的點
在四維偏序的算法中,那就是左邊的點可以對右邊的點做出貢獻(僅在當前維度下)
這樣就強行消除了一個維度的限制.
四維偏序
COGS 2479
題目大意
給定一個有\(n\)個元素的序列,元素編號為\(1~n\),每個元素有三個屬性\(a,b,c\),求序列中滿足\(i<j\)且\(a_i<a_j\)且\(b_i<b_j\)且\(c_i<c_j\)的數對\((i,j)\)的個數。
題解
我們把下標也看作一個維度,那么這就是個四維偏序
我們在下標的維度上CDQ
然后記錄每個元素在第一次CDQ中是較小的還是較大的.
因為只有較小的元素才能對較大的元素做出貢獻
只有較大的元素才能接受較小的元素的影響.
所以我們處理出來后這就變成了一個三維偏序
所以我們在對這個序列(CDQ+掃描線+樹狀數組)求三維偏序即可
Code
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; inline void read(int &x){x=0;char ch;bool flag = false;while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x; } const int maxn = 50010; struct Node{int a,b,c;bool is_sm;Node(){a=b=c=is_sm = 0;} }a[maxn],tmp1[maxn],tmp2[maxn]; int c[maxn],n,init_tmp[maxn],ans=0; #define lowbit(x) (x&-x) inline void modify(int x,int y){for(;x<=n;x+=lowbit(x)) c[x] += y; } inline int query(int x){int ret = 0;for(;x;x-=lowbit(x)) ret += c[x];return ret; } void solve2(int l,int r){if(l == r) return ;int mid = l+r >> 1;solve2(l,mid);solve2(mid+1,r);int i = l,j = mid+1,k = l;Node *a = tmp1,*tmp = tmp2;init_tmp[0] = 0;while(i <= mid || j <= r){if((j > r) || (i <= mid && a[i].b < a[j].b)){if( a[i].is_sm){modify(a[i].c,1);init_tmp[++init_tmp[0]] = i;}tmp[k++] = a[i++];}else{if(!a[j].is_sm){ans += query(a[j].c);}tmp[k++] = a[j++];}}for(int i = 1;i<=init_tmp[0];++i) modify(a[init_tmp[i]].c,-1);copy(tmp+l,tmp+r+1,a+l); } void solve1(int l,int r){if(l == r) return ;int mid = l+r >> 1;solve1(l,mid);solve1(mid+1,r);int i = l,j = mid+1,k = l;Node *tmp = tmp1;while(i <= mid || j <= r){if((j > r) || (i <= mid && a[i].a < a[j].a)){(tmp[k++] = a[i++]).is_sm = true;}else (tmp[k++] = a[j++]).is_sm = false;}copy(tmp+l,tmp+r+1,a+l);solve2(l,r); } int main(){ // freopen("partial_order.in","r",stdin); // freopen("partial_order.out","w",stdout);read(n);for(int i=1;i<=n;++i) read(a[i].a);for(int i=1;i<=n;++i) read(a[i].b);for(int i=1;i<=n;++i) read(a[i].c);solve1(1,n);printf("%d\n",ans);getchar();getchar();return 0; }轉載于:https://www.cnblogs.com/Skyminer/p/6405323.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的四维偏序 CDQ套CDQ的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单一码付:将支付宝和微信的收款二维码合
- 下一篇: pdf打印机如何设置双面打印