P3810 【模板】三维偏序(陌上花开) 题解(cdq分治模板)
题目链接
题目思路
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;
}
不摆烂了,写题