以前的树套树第一题,好像也是除了二维线段树和二维bit的唯一一道树套树。
三维偏序是很裸的cdq,注意排序时,一是cdq里面sort的时候不能说按x为第一关键字就只比较第一关键字,这可能导致y1处的修改在y2的询问后面(y1<=y2),第二个是用重载的 < 比cmp快很多很多,把cdq里面的cmp去了之后快了1s。
//QWsin
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100000+10;
const int maxk=200000+10;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
int n,k;
struct Node{
int x,y,z,t,id;
inline void input(int i){id=i;x=read();y=read();z=read();}
bool operator != (const Node &rhs)const{
return x!=rhs.x||y!=rhs.y||z!=rhs.z;
}
inline bool operator < (const Node &rhs)const{
if(y!=rhs.y) return y<rhs.y;
if(x!=rhs.x) return x<rhs.x;
return z<rhs.z;
}
}x[maxn],t[maxn];
int ans[maxn],cnt[maxn],num[maxn];
int cmp1(Node a,Node b){
if(a.x!=b.x) return a.x<b.x;
if(a.y!=b.y) return a.y<b.y;
return a.z<b.z;
}
int id[maxn];
int C[maxk];
#define lowbit(i) ((i)&-(i))
inline void updata(int pos,int val){
for(int i=pos;i<=k;i+=lowbit(i)) C[i]+=val;
}
inline int query(int pos){
int ret=0;
for(int i=pos;i;i-=lowbit(i)) ret+=C[i];
return ret;
}
void solve(int l,int r)
{
if(l>=r) return ;
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
for(int i=l;i<=mid;++i) x[i].t=0;
for(int i=mid+1;i<=r;++i) x[i].t=1;
for(int i=l;i<=r;++i) t[i]=x[i];
sort(t+l,t+r+1);
for(int i=l;i<=r;++i)
if(!t[i].t) updata(t[i].z,num[t[i].id]);
else ans[t[i].id]+=query(t[i].z);
for(int i=l;i<=r;++i)
if(!x[i].t) updata(x[i].z,-num[x[i].id]);
}
char s[20];int p;
inline void output(int x){
if(!x) {putchar('0');}
else{
for(p=0;x;x/=10) s[++p]=x%10+'0';
for(int i=p;i>=1;--i) putchar(s[i]);
}
putchar('\n');
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;++i) t[i].input(i);
sort(t+1,t+n+1,cmp1);
int p=0;
for(int i=1;i<=n;++i)
{
if(i==1||t[i]!=t[i-1]) x[++p]=t[i],num[p]=1,x[p].id=p;
else ++num[p];
}
solve(1,p);
for(int i=1;i<=n;++i) cnt[ans[i]+num[i]-1]+=num[i];
for(int i=0;i<n;++i) output(cnt[i]);
return 0;
}