这就是个三维的归并排序…
初始排序消掉一维 ( a ) (a) (a)
归并排序消掉一维 ( b ) (b) (b)
树状数组解决一维 ( c ) (c) (c)
当然这只是模板不是讲解,想看讲解移步全是讲解
#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
struct p{
int a,b,c,cnt,ans;
}s1[maxn],s2[maxn];
int n,k,top,sumn[maxn],su[maxn];
bool com1(p q,p w){
if( q.a!=w.a ) return q.a<w.a;
if( q.b!=w.b ) return q.b<w.b;
return q.c<w.c;
}
bool com2(p q,p w){
if( q.b!=w.b ) return q.b<w.b;
return q.c<w.c;
}
int lowbit(int x){ return x&(-x); }
void add(int x,int s){
for(;x<=k;x+=lowbit(x) ) sumn[x]+=s;
}
int ask(int x){
int ans=0;
for(;x;x-=lowbit(x) ) ans+=sumn[x];
return ans;
}
int query(int x)
{
int sum=0;
while(x)
{
sum+=sumn[x];
x-=lowbit(x);
}
return sum;
}//求单点前缀和
void cdq(int l,int r)
{
if( l==r ) return;
int mid=l+r>>1;
cdq(l,mid); cdq(mid+1,r);
sort(s2+l,s2+mid+1,com2);
sort(s2+mid+1,s2+r+1,com2);
int j=l;
for(int i=mid+1;i<=r;i++)
{
while( j<=mid&&s2[i].b>=s2[j].b)//j还可以为i做出贡献,j往后挪
{
add( s2[j].c,s2[j].cnt );
j++;
}
s2[i].ans+=ask( s2[i].c );
}
for(int i=l;i<j;i++) add( s2[i].c,-s2[i].cnt);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&s1[i].a,&s1[i].b,&s1[i].c);
s1[i].cnt=1,s1[i].ans=0;
}
sort(s1+1,s1+1+n,com1);
s2[++top]=s1[1];
for(int i=2;i<=n;i++)
{
if( s1[i].a==s1[i-1].a&&s1[i].b==s1[i-1].b&&s1[i].c==s1[i-1].c ) s2[top].cnt++;
else s2[++top]=s1[i];
}
cdq(1,top);
for(int i=1;i<=top;i++)
su[ s2[i].ans+s2[i].cnt-1 ]+=s2[i].cnt;
//算上元素内部的贡献s2[cnt]-1
for(int i=0;i<n;i++) printf("%d\n",su[i] );
}