COGS 2479. [HZOI 2016] 偏序 (CDQ套CDQ)
解题思路
四维偏序问题,模仿三维偏序,第一维排序,第二维CDQ,最后剩下二元组,发现没办法处理,就继续嵌套CDQ分治。首先把二元组的左右两边分别打上不同的标记,因为统计答案时只统计左边对右边的影响,然后再进行一个CDQ解决第三维,最后用树状数组解决最后一维。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; const int MAXN = 50005; const int LEFT = 1; const int RIGHT = 2; typedef long long LL; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n; LL ans,f[MAXN]; struct Query{ int a,b,c,id,New; }q[MAXN],tmp[MAXN],tmp_[MAXN]; void update(int x,int k){ for(;x<=n;x+=x&-x) f[x]+=k; } LL query(int x){ LL ret=0; for(;x;x-=x&-x) ret+=f[x]; return ret; } void Clear(int x){ for(;x<=n;x+=x&-x) f[x]=0; } void CDQ(int l,int r){ if(l==r) return; int mid=l+r>>1;CDQ(l,mid);CDQ(mid+1,r); int L=l,R=mid+1,o=l; while(L<=mid && R<=r){ if(tmp[L].b<tmp[R].b){ if(tmp[L].New==LEFT) update(tmp[L].c,1); tmp_[o++]=tmp[L++]; } else{ if(tmp[R].New==RIGHT) ans+=query(tmp[R].c); tmp_[o++]=tmp[R++]; } } while(L<=mid) tmp_[o++]=tmp[L++]; while(R<=r) { if(tmp[R].New==RIGHT) ans+=query(tmp[R].c); tmp_[o++]=tmp[R++]; } // memset(f,0,sizeof(f)); for(register int i=l;i<=mid;i++) if(tmp[i].New==LEFT) Clear(tmp[i].c); for(register int i=l;i<=r;i++) tmp[i]=tmp_[i]; } void cdq(int l,int r){ if(l==r) return; int mid=l+r>>1;cdq(l,mid);cdq(mid+1,r); int L=l,R=mid+1,o=l; while(L<=mid && R<=r){ if(q[L].a<q[R].a) { q[L].New=LEFT; tmp[o++]=q[L++]; } else { q[R].New=RIGHT; tmp[o++]=q[R++]; } } while(L<=mid) {q[L].New=LEFT;tmp[o++]=q[L++];} while(R<=r) {q[R].New=RIGHT;tmp[o++]=q[R++];} for(register int i=l;i<=r;i++) q[i]=tmp[i]; CDQ(l,r); } int main(){ // freopen("data.txt","r",stdin); // freopen("wrong.txt","w",stdout); freopen("partial_order.in","r",stdin); freopen("partial_order.out","w",stdout); n=rd(); for(int i=1;i<=n;i++) q[i].a=rd(),q[i].id=i; for(int i=1;i<=n;i++) q[i].b=rd(); for(int i=1;i<=n;i++) q[i].c=rd(); cdq(1,n);cout<<ans<<endl; return 0; }