一、题目
二、解法
的板题,首先对 从小到大排序,然后考虑合并两段,因为已经保证了 的顺序,我们先对 排序,然后扫右边,把左边 小于等于当前值的加入树状数组,然后查询 比当前值小的个数和。
有一个细节就是 三个值都相等的时候要合并成一个。
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 200005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,cnt[M],bit[M];
struct node
{
int a,b,c,w,ans;
}p[M];
bool cmp1(node x,node y)
{
if(x.a==y.a)
{
if(x.b==y.b) return x.c<y.c;
return x.b<y.b;
}
return x.a<y.a;
}
bool cmp2(node x,node y)
{
if(x.b==y.b) return x.c<y.c;
return x.b<y.b;
}
int lowbit(int x)
{
return x&(-x);
}
void ins(int x,int f)
{
for(int i=x;i<=k;i+=lowbit(i))
bit[i]+=f;
}
int ask(int x)
{
int r=0;
for(int i=x;i>=1;i-=lowbit(i))
r+=bit[i];
return r;
}
void cdq(int l,int r)
{
if(l==r) return ;
int mid=(l+r)>>1,i=l;
cdq(l,mid);cdq(mid+1,r);
sort(p+l,p+mid+1,cmp2);
sort(p+mid+1,p+r+1,cmp2);
for(int j=mid+1;j<=r;j++)
{
while(i<=mid && p[i].b<=p[j].b)
{
ins(p[i].c,p[i].w);i++;
}
p[j].ans+=ask(p[j].c);
}
for(i--;i>=l;i--)
ins(p[i].c,-p[i].w);
}
int main()
{
m=read();k=read();
for(int i=1;i<=m;i++)
{
p[i].a=read();
p[i].b=read();
p[i].c=read();
}
sort(p+1,p+1+m,cmp1);
for(int i=1,c=0;i<=m;i++)
{
c++;
if(p[i].a!=p[i+1].a || p[i].b!=p[i+1].b || p[i].c!=p[i+1].c)
p[++n]=p[i],p[n].w=c,c=0;
}
cdq(1,n);
for(int i=1;i<=n;i++)
cnt[p[i].ans+p[i].w-1]+=p[i].w;
for(int i=0;i<m;i++)
printf("%d\n",cnt[i]);
}