题目背景https://www.luogu.org/problemnew/show/P3810

这是一道模板题

可以使用bitset,CDQ分治,K-DTree等方式解决。

题目描述

 

 

 

 

 

 

 

 

 

 

输入输出样例

输入样例#1: 复制

10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1

输出样例#1: 复制

3
1
3
0
1
0
1
0
0
1

说明

1≤n≤100000,1≤k≤200000 1 \leq n \leq 100000, 1 \leq k \leq 200000 1≤n≤100000,1≤k≤200000

cdq分治每次计算前一半对后一半的影响。具体地, 假设三维分别是x,y,z,先按x排序。分治时每次将前半边、后半边分别按y排序。虽然现在x的顺序被打乱了,但是前半边还是都小于后半边的,所以要是只计算前半边对后半边的偏序关系,是不会受到x的影响的。维护后一半的指针i,前一半的指针j,每次将i后移一位时,若y[j]<=y[i]则不断后移j,并不断将z[j]加入树状数组。然后再查询树状数组中有多少数小于等于z[i]。 最后要清空树状数组。

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
int Tree[maxn+10];
struct node
{
    int a,b,c;
    int ans;
    int num;
};
node p[maxn];
node q[maxn];
int cnt[maxn];
bool cmpa(const node &a,const node &b)
{
    if(a.a==b.a)
    {
        if(a.b==b.b)
            return a.c<b.c;
        return a.b<b.b;
    }
    return a.a<b.a;
}
bool cmpb(const node &a,const node &b)
{
    return a.b<b.b;
}
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*f;
}
inline int lowbit(int x)
{
    return (x&-x);
}
void add(int x,int value)
{
    for(int i=x; i<=maxn; i+=lowbit(i))
    {
        Tree[i]+=value;
    }
}
int get(int x)
{
    int sum=0;
    for(int i=x; i; i-=lowbit(i))
    {
        sum+=Tree[i];
    }
    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(q+l,q+mid+1,cmpb);
    sort(q+mid+1,q+r+1,cmpb);
    int i=l,j=mid+1;
    for(; j<=r; j++)
    {
        while(i<=mid&&q[i].b<=q[j].b)
        {
            add(q[i].c,q[i].num);
            i++;
        }
        q[j].ans+=get(q[j].c);
    }
    for(j=l; j<i;j++)
        add(q[j].c,-q[j].num);
}
int main()
{
    memset(cnt,0,sizeof(maxn));
    int n=0,n_,k;
    n_=read();
    k=read();
    for(int i=0; i<n_; i++)
    {
        p[i].a=read();
        p[i].b=read();
        p[i].c=read();
        p[i].ans=0;
    }
    sort(p,p+n_,cmpa);
    for(int i=0;i<n_;i++)
    {
        int num=0;
        if(q[n].a!=p[i].a||q[n].b!=p[i].b||q[n].c!=p[i].c)
        {
            n++;
            q[n].a=p[i].a;
            q[n].b=p[i].b;
            q[n].c=p[i].c;
            q[n].num=1;
        }
        else
            q[n].num++;
    }//得到a b c 都不同的数组  num是出现的次数
    cdq(1,n);
    for(int i=1; i<=n; i++)
    {
        cnt[q[i].ans+q[i].num-1]+=q[i].num;
    }
    for(int i=0; i<n_; i++)
    {
        printf("%d\n",cnt[i]);
    }
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+15;
struct node{
int a,b,c,w,ans;
};
map<pair<int,pair<int,int> >,int >mp;
bool cmpb(const node &a,const node &b)
{
    return a.b<b.b;
}
node p[maxn];
int tree[maxn];
int num[maxn];
inline int lowbit(int x)
{
    return (x&-x);
}
void add(int x,int value)
{
    for(int i=x;i<maxn;i+=lowbit(i))
        tree[i]+=value;
}
int get(int x)
{
    int sum=0;
    for(int i=x;i;i-=lowbit(i))
    {
        sum+=tree[i];
    }
    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(p+l,p+mid+1,cmpb);
    sort(p+mid+1,p+r+1,cmpb);
    int i=l;
    int j=mid+1;
    for(;j<=r;j++)
    {
        while(p[i].b<=p[j].b&&i<=mid)
        {
            add(p[i].c,p[i].w);
            i++;
        }
        p[j].ans+=get(p[j].c);
    }
    i--;
    for(;i>=l;i--)
        add(p[i].c,-p[i].w);
}
int main()
{
    int n,k;
    memset(num,0,sizeof(num));
    int a,b,c;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        mp[make_pair(a,make_pair(b,c))]++;
    }
    int cnt=0;
    for(auto it=mp.begin();it!=mp.end();it++)
    {
        p[cnt].a=(it->first).first;
        p[cnt].b=(it->first).second.first;
        p[cnt].c=(it->first).second.second;
        p[cnt].w=(it->second);
        p[cnt].ans=0;
        cnt++;
    }//去重
    cdq(0,cnt-1);
    for(int i=0;i<cnt;i++)
    {
        num[p[i].ans+p[i].w-1]+=p[i].w;
    }
    for(int i=0;i<n;i++)
    {
        printf("%d\n",num[i]);
    }
    return 0;
}