链接

https://www.luogu.org/problemnew/show/P3810

题解

首先按照a、b、c的优先级排序,这样第一维已经有序了
考虑第二维使用CDQ分治
在递归合并的时候,按照b的大小关系合并
左侧对右侧的影响是,首先a、b已经满足条件(在排序的时候,和合并时候),c有可能满足,所以在树状数组上更新c的值,当右侧统计答案时,在树状数组上查找小于等于c的个数即可
注意,为了方便统计,需要将完全相同的合并并计数,在树状数组更新的值就是个数

代码

#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;

struct node{
    int a,b,c,w,ans;
    bool operator < (const node z) const{
        return a==z.a?(b==z.b?c<z.c:b<z.b):a<z.a;
    }
}q[N],tmp[N];
int ans[N],bar[N],d[N<<1],n,m,T;

inline void up(int x,int p){for (;x<=T;x+=x&-x) d[x]+=p;}
inline int sum(int x){int t=0;for (;x;x-=x&-x) t+=d[x]; return t;}

void CDQ(int l,int r){
    if (l==r) return;
    int t=l+r>>1,x=l,y=t+1,k=l;
    CDQ(l,t);
    CDQ(t+1,r);
    while(x<=t && y<=r){
        if (q[x].b<=q[y].b){
            up(q[x].c,q[x].w);
            tmp[k++]=q[x++];
        } else {
            q[y].ans+=sum(q[y].c);
            tmp[k++]=q[y++];
        }
    }
    while(y<=r){
        q[y].ans+=sum(q[y].c);
        tmp[k++]=q[y++];
    }
    for (int i=l;i<x;i++)  up(q[i].c,-q[i].w);
    while(x<=t) tmp[k++]=q[x++];
    for (int i=l;i<=r;i++) q[i]=tmp[i];
}

int main(int argc, char const *argv[])
{

    scc(n,T); m=1;
    for (int i=1;i<=n;i++)
        sccc(q[i].a,q[i].b,q[i].c),q[i].w=1;

    sort(q+1,q+n+1);

    for (int i=2;i<=n;i++)
        if (q[i].a==q[m].a&&q[m].b==q[i].b&&q[m].c==q[i].c) q[m].w++;
    else
        q[++m]=q[i];

    CDQ(1,m);

    for (int i=1;i<=m;i++)
        bar[q[i].ans+q[i].w-1]+=q[i].w;

    for (int i=0;i<n;i++) printf("%d\n",bar[i]);
    return 0;
}