做题记录整理分治2 P3810 【模板】三维偏序(陌上花开)(2022/9/15)
CDQ分治,先用第一维排序,用第二维归并排序,第三维再上树状数组
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node {
int x;
int y;
int z;
int cnt,ans;
} a[500005],b[500005];
int n,m,k;
int ans[500005];
int c[500005];
bool cmp1(node x,node y) { //第一维排序
if(x.x==y.x) {
if(x.y==y.y)return x.z<y.z;
else return x.y<y.y;
} else return x.x<y.x;
}
bool cmp2(node x,node y) { //第二维排序
if(x.y==y.y)
return x.z<y.z;
else return x.y<y.y;
}
int lb(int x) {
return x&(-x);
}
void xg(int x,int y) {
while(x<=k) {
c[x]+=y;
x+=lb(x);
}
}
int qh(int x) {
int ansm=0;
while(x) {
ansm+=c[x];
x-=lb(x);
}
return ansm;
}
void cdq(int l,int r) {//cdq分治
if(l==r)return;
int mid=(l+r)>>1;
cdq(l,mid);
cdq(mid+1,r);
sort(b+l,b+mid+1,cmp2);
sort(b+mid+1,b+r+1,cmp2);//第二维为关键字排序
int j=l;
for1(i,mid+1,r) {
while(b[i].y>=b[j].y&&j<=mid) {
xg(b[j].z,b[j].cnt);
j++;
}
b[i].ans+=qh(b[i].z);
}
for1(i,l,j-1)
xg(b[i].z,-b[i].cnt);//清空树状数组
}
int main() {
scanf("%d%d",&n,&k);
for1(i,1,n)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+1+n,cmp1);//第一维为关键字排序
int ji=0;
for1(i,1,n) {
ji++;
if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y||a[i].z!=a[i+1].z) {
b[++m].x=a[i].x;
b[m].y=a[i].y;
b[m].z=a[i].z;
b[m].cnt=ji;
ji=0;
}
}//去重
cdq(1,m);
for1(i,1,m) ans[b[i].ans+b[i].cnt-1]+=b[i].cnt;
for1(i,0,n-1)
printf("%d\n",ans[i]);
return 0;
}

浙公网安备 33010602011771号