1. 程式人生 > >洛谷 P3810 【模板】三維偏序(陌上花開) (cdq分治模板)

洛谷 P3810 【模板】三維偏序(陌上花開) (cdq分治模板)

三維 答案 就是 mes esp while lowbit -- cst

在solve(L,R)中,需要先分治solve兩個子區間,再計算左邊區間修改對右邊區間詢問的貢獻。

註意,計算額外的貢獻時,兩子區間各自內部的順序變得不再重要(不管怎麽樣左邊區間的都發生在右邊之前),於是就少了一維


https://www.lydsy.com/JudgeOnline/problem.php?id=3262

https://www.luogu.org/problemnew/show/P3810

此題每個操作既是修改又是查詢

對於此題,先按一維排序,在solve(L,R)中先solve兩個子區間,然後把L到R的操作按二維排序(由於cdq分治類似歸並的特性此時兩個子區間內部二維都是有序的,可以直接二路歸並),然後就是一個對二、三維求逆序對的過程(只不過只有歸並前在第一個區間內的修改生效,歸並前在第二個區間內的查詢要更新答案)

可以記一下每個元素在按第一維排序後的編號(以下代碼中q[i].num),來判斷它歸並前是哪個區間裏的

註意:此題第一維相同的實際並不存在順序關系,理應同時處理然後同時計算貢獻,但排序後它們間總是要存在一個特定順序的,所以要加一些奇怪的特判

具體的話:首先一開始排序的時候三個關鍵字都要依次考慮(而不是只考慮第一維),這樣可以保證排序後大部分情況下後面的不會對前面產生貢獻

上面還漏考慮了完全相等的三元組,如果它們存在則後面也會對前面產生貢獻。因此只要在開始solve前補上這些後面對前面產生的貢獻即可

歸並可以簡化為

merge(q+lp,q+mid+1,q+mid+1,q+rp+1
,tmp+lp); copy(tmp+lp,tmp+rp+1,q+lp);

inplace_merge(q+lp,q+mid+1,q+rp+1);
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 struct Q
 5 {
 6     int a,b,c,ans,num;
 7 }q[100100],tmp[100100];
 8 int n,k;
 9 bool c1(const Q &a,const Q &b)    {return
a.a<b.a||(a.a==b.a&&a.b<b.b)||(a.a==b.a&&a.b==b.b&&a.c<b.c);} 10 bool operator<(const Q &a,const Q &b) {return a.b<b.b||(a.b==b.b&&a.num<b.num);} 11 bool operator==(const Q &a,const Q &b) {return a.a==b.a&&a.b==b.b&&a.c==b.c;} 12 int dat[200100]; 13 const int N=200000; 14 #define lowbit(x) ((x)&(-x)) 15 void addx(int pos,int d) 16 { 17 for(;pos<=N;pos+=lowbit(pos)) dat[pos]+=d; 18 } 19 int sum(int pos) 20 { 21 int ans=0; 22 for(;pos>0;pos-=lowbit(pos)) ans+=dat[pos]; 23 return ans; 24 } 25 int num[100100]; 26 void solve(int lp,int rp) 27 { 28 if(lp==rp) return; 29 int mid=lp+(rp-lp)/2; 30 solve(lp,mid);solve(mid+1,rp); 31 int k=lp-1,i,j; 32 for(i=lp,j=mid+1;i<=mid&&j<=rp;) 33 { 34 ++k; 35 if(q[i]<q[j]) tmp[k]=q[i++]; 36 else tmp[k]=q[j++]; 37 } 38 while(i<=mid) tmp[++k]=q[i++]; 39 while(j<=rp) tmp[++k]=q[j++]; 40 for(i=lp;i<=rp;i++) q[i]=tmp[i]; 41 for(i=lp;i<=rp;i++) 42 { 43 if(q[i].num<=mid) addx(q[i].c,1); 44 else q[i].ans+=sum(q[i].c); 45 } 46 for(i=lp;i<=rp;i++) 47 if(q[i].num<=mid) 48 addx(q[i].c,-1); 49 } 50 int main() 51 { 52 int i,j,t,tt=0; 53 scanf("%d%d",&n,&t); 54 for(i=1;i<=n;i++) scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].c); 55 sort(q+1,q+n+1,c1); 56 for(i=1;i<=n;i++) 57 { 58 tt++; 59 if(i==n||!(q[i]==q[i+1])) 60 { 61 for(j=i-tt+1,t=tt-1;j<=i;j++) q[j].ans+=t,--t; 62 tt=0; 63 } 64 } 65 for(i=1;i<=n;i++) q[i].num=i; 66 solve(1,n); 67 for(i=1;i<=n;i++) num[q[i].ans]++; 68 for(i=0;i<n;i++) printf("%d\n",num[i]); 69 return 0; 70 }

洛谷 P3810 【模板】三維偏序(陌上花開) (cdq分治模板)