C78 二维线段树+动态开点 点修+区查 P3810 三维偏序(陌上花开)
视频链接:264 二维线段树+动态开点 点修+区查 P3810 三维偏序(陌上花开)_哔哩哔哩_bilibili
// 二维线段树+动态开点 点修+区查 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; void read(int &x){ //快读 x=0; char c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c))x=x*10+c-'0',c=getchar(); } #define N 100005 #define mid ((l+r)>>1) int n,k,ans[N],last; struct node{ int a,b,c; bool operator<(node t){return a<t.a;} }g[N]; //属性 int lsx[N*20],rsx[N*20],lsy[N*200],rsy[N*200]; int root,rt[N*20],d[N*200],totx,toty; void changeY(int &u,int l,int r,int i){ //内修 if(!u) u=++toty; //内树开点 d[u]+=1; //d[u]的经过次数 if(l==r) return; if(g[i].c<=mid) changeY(lsy[u],l,mid,i); else changeY(rsy[u],mid+1,r,i); } void changeX(int &u,int l,int r,int i){ //外修 if(!u) u=++totx; //外树开点 changeY(rt[u],1,k,i); //外层入内 if(l==r) return; if(g[i].b<=mid) changeX(lsx[u],l,mid,i); else changeX(rsx[u],mid+1,r,i); } int queryY(int u,int l,int r,int y1,int y2,int i){ //内查 if(y1<=l&&r<=y2) return d[u]; //内层覆盖即返回 int res=0; if(y1<=mid) res+=queryY(lsy[u],l,mid,y1,y2,i); if(y2>=mid+1) res+=queryY(rsy[u],mid+1,r,y1,y2,i); return res; } int queryX(int u,int l,int r,int x1,int x2,int i){ //外查 if(x1<=l&&r<=x2) return queryY(rt[u],1,k,1,g[i].c,i); //外层覆盖即入内 int res=0; if(x1<=mid) res+=queryX(lsx[u],l,mid,x1,x2,i); if(x2>=mid+1) res+=queryX(rsx[u],mid+1,r,x1,x2,i); return res; } int main(){ read(n),read(k); //n元素数量,k最大属性值 for(int i=1;i<=n;i++) read(g[i].a),read(g[i].b),read(g[i].c); sort(g+1,g+1+n); //按属性a升序 last=1; for(int i=1;i<=n;i++){ changeX(root,1,k,i); //点修 if(g[i+1].a!=g[i].a){ for(int j=last;j<=i;j++) ans[queryX(root,1,k,1,g[j].b,j)-1]++; last=i+1; } } for(int i=0;i<n;i++) printf("%d\n",ans[i]); }