三维偏序(陌上花开) CDQ分治

十分巧妙。

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 200000
#define N 3000000
#define ll long long
using namespace std;
int k,n;
int C[N],ans[maxn],cnt[maxn];  
int lowbit(int x){ return x&(-x); }
void add(int pos,int x){
    while(pos<=k) C[pos]+=x,pos+=lowbit(pos); 
}
int query(int pos){
    int sum=0;
    while(pos>0) sum+=C[pos],pos-=lowbit(pos); 
    return sum; 
}
struct OPT{
    int x,y,z,w,idx; 
}arr[maxn],opt[maxn]; 
int cmpx(OPT a,OPT b){ return (a.x==b.x&&a.y==b.y)?(a.z<b.z):((a.x==b.x)?a.y<b.y:a.x<b.x); }
int cmpy(OPT a,OPT b){ return (a.y==b.y)?a.z<b.z:a.y<b.y; }
void solve(int l,int r){
    if(l>=r) return;
    int mid=(l+r)>>1;
    solve(l,mid),solve(mid+1,r);
    sort(opt+l,opt+mid+1,cmpy),sort(opt+mid+1,opt+r+1,cmpy);
    int p=l,q=mid+1;
    for(;q<=r;++q){
        while(opt[p].y<=opt[q].y&&p<=mid) add(opt[p].z,opt[p].w),++p; 
        ans[opt[q].idx]+=query(opt[q].z); 
    }
    for(int i=l;i<p;++i) add(opt[i].z,-opt[i].w); 
}
int main()
{
    //setIO("input"); 
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)scanf("%d%d%d",&arr[i].x,&arr[i].y,&arr[i].z);
    sort(arr+1,arr+1+n,cmpx);
    int u=n,cc=0; 
    n=0; 
    for(int i=1;i<=u;++i){
        ++cc;
        if(arr[i].x!=arr[i+1].x||arr[i].y!=arr[i+1].y||arr[i].z!=arr[i+1].z) 
            opt[++n]=arr[i],opt[n].w=cc,opt[n].idx=n,cc=0; 
    }
    solve(1,n); 
    for(int i=1;i<=n;i++)
        cnt[ans[opt[i].idx]+opt[i].w-1]+=opt[i].w;
    for(int i=0;i<u;++i) printf("%d
",cnt[i]); 
    return 0; 
}

  

原文地址:https://www.cnblogs.com/guangheli/p/10259786.html