一,偏序性质
二,二维偏序
三,三维偏序
- 第一维:使用三关键次排序自然保证
- 第二维:使用双指针维护位置(排序后数组单调)
- 第三维:动态添加,使用轻量化动态前缀和数据结构:树状数组
注意:
1,重复元素需要记次数,最后单独计算贡献,否则CDQ会出错
2,归并排序和答案统计使用的是去重之后的数组
3,重新定义小于号注意最后一步写法,不要出现没有返回值的情况
4,注意重复统计的方法
bool operator < (const node &x,const node &y)
{
if(x.a!=y.a)return x.a<y.a;
else if (x.b!=y.b) return x.b<y.b;
else return x.c<y.c;
}
bool operator == (const node &x,const node &y)
{
return x.a==y.a && x.b==y.b && x.c==y.c;
}
void merge_sort(int l,int r)
{
if(l==r)return;
int mid = (l+r)>>1;
merge_sort(l,mid); merge_sort(mid+1,r);
int i=l; int j=mid+1;
int k=0;
while (i<=mid && j<=r)
{
if(q[i].b<=q[j].b) add(q[i].c,q[i].s) , w[k++]=q[i++];
else q[j].res+=query(q[j].c) , w[k++]=q[j++];
}
while (i<=mid) add(q[i].c,q[i].s) , w[k++]=q[i++];
while (j<=r) q[j].res+=query(q[j].c) , w[k++]=q[j++];
for(i=l;i<=mid;i++) add(q[i].c,-q[i].s);
for(int ii=l,jj=0;jj<k;jj++,ii++)q[ii]=w[jj];
}
int main()
{
read(n); read(m);
rep(i,0,n-1)
{
int a,b,c;
read(a); read(b); read(c);
q[i]={a,b,c,1};
}
sort(q,q+n);
int k=1;
rep(i,1,n-1)
{
if(q[i]==q[k-1])q[k-1].s++;
else q[k++]=q[i];
}
merge_sort(0,k-1);
rep(i,0,k-1)ans[q[i].res+q[i].s-1]+=q[i].s;
rep(i,0,n-1) wri(ans[i]),puts("");
}