P3810 【模板】三維偏序(陌上花開) 題解(cdq分治模板)
阿新 • • 發佈:2021-09-16
題目連結
題目思路
cdq分治其實就是歸併排序的思維
這個題目就是cdq套一個線段樹就行
但是要注意有些點的座標相同,要先去重,然後再寫
程式碼
不擺爛了,寫題#include<bits/stdc++.h> #define fi first #define se second #define debug cout<<"I AM HERE"<<endl; using namespace std; typedef long long ll; const int maxn=5e5+5,inf=0x3f3f3f3f,mod=1e9+7; const double eps=1e-6; int n,m,k; struct node{ int x,y,z,cnt,ans; }a[maxn],b[maxn],c[maxn]; int tree[maxn<<2]; int dp[maxn]; int pr[maxn]; ll ans=0; void update(int node,int l,int r,int pos,int val){ if(l==r){ if(val==-1){ tree[node]=0; }else{ tree[node]+=val; } return ; } int mid=(l+r)/2; if(mid>=pos) update(node<<1,l,mid,pos,val); else update(node<<1|1,mid+1,r,pos,val); tree[node]=tree[node<<1]+tree[node<<1|1]; } int query(int node,int L,int R,int l,int r){ if(L<=l&&r<=R){ return tree[node]; } int mid=(l+r)/2,sum=0; if(mid>=L) sum+=query(node<<1,L,R,l,mid); if(mid<R) sum+=query(node<<1|1,L,R,mid+1,r); return sum; } void cdq(int l,int r){ if(l>=r){ return ; } int mid=(l+r)/2; cdq(l,mid); cdq(mid+1,r); int pos1=l,pos2=mid+1,id=l; while(pos1<=mid&&pos2<=r){ if(a[pos1].y<=a[pos2].y){ update(1,1,k,a[pos1].z,a[pos1].cnt); b[id++]=a[pos1++]; }else{ a[pos2].ans+=query(1,1,a[pos2].z,1,k); b[id++]=a[pos2++]; } } while(pos1<=mid) b[id++]=a[pos1++]; while(pos2<=r) a[pos2].ans+=query(1,1,a[pos2].z,1,k),b[id++]=a[pos2++]; for(int i=l;i<=r;i++){ update(1,1,k,b[i].z,-1); a[i]=b[i]; } } bool cmp(node a,node b){ if(a.x!=b.x){ return a.x<b.x; }else if(a.y!=b.y){ return a.y<b.y; }else{ return a.z<b.z; } } signed main(){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); } sort(a+1,a+1+n,cmp); int sum=0; for(int i=1;i<=n;i++){ sum++; if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y||a[i].z!=a[i+1].z){ m++; c[m]=a[i]; c[m].cnt=sum; sum=0; } } for(int i=1;i<=m;i++){ a[i]=c[i]; a[i].ans=0; } cdq(1,m); for(int i=1;i<=m;i++){ int temp=a[i].cnt; while(temp--){ pr[a[i].ans+a[i].cnt-1]++; } } for(int i=0;i<=n-1;i++){ printf("%d\n",pr[i]); } return 0; }