P3810 陌上花開(三維偏序,cdq分治模板)

https://www.luogu.org/problem/P3810

 

//第一維排序,第二維cdq分治,第三維樹狀數組
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&-(x))
const int maxn = 200006;
int a[200009],ans[200009];
struct flower
{
    int x,y,z,sum,cnt;
    bool operator==(const flower &p)const
    {
        return x==p.x&&y==p.y&&z==p.z;
    }

} p[100009];
bool cmp1(flower a, flower b)
{
    if(a.x != b.x)
        return a.x < b.x;
    if(a.y!=b.y)
        return a.y<b.y;
    return a.z < b.z;
}
bool cmp2(flower a, flower b)
{
    return a.y < b.y;
}
void add(int x, int y)
{
    for(int i = x; i<=maxn; i+=lowbit(i))
    {
        a[i] += y;
    }
}
int sum(int x)
{
    int ans = 0;
    for(int i = x; i; i-=lowbit(i))
    {
        ans +=a[i];
    }
    return ans;
}

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,cmp2);
    sort(p+mid+1,p+r+1,cmp2);
    int i,j = l;

    //解決左半部分對右半部分的貢獻(右半部分對左半部分無貢獻)
    for(i = mid+1; i<= r; i++)//遞歸右半部分
    {
        for(; j<=mid&&p[j].y<=p[i].y; j++)//左半部分x,y值小於右半部分的,樹狀數組記錄
        {
            add(p[j].z,p[j].cnt);
        }
        p[i].sum += sum(p[i].z);
    }

    for(i = l; i<j; i++)//把樹狀數組清空
    {
        add(p[i].z,-p[i].cnt);
    }

}

int main()
{
    int k,i,j,m,n;
    scanf("%d %d",&n, &m);
    for(i = 1; i <= n; i++)
    {
        scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].z);
        p[i].sum = p[i].cnt = 0;
    }
    memset(a,0,sizeof(a));
    sort(p+1,p+n+1,cmp1);
    k = 0;
    for(i = 1; i <= n; i++)//去重
    {
        for(j = i; p[i]==p[j]&&j<=n; j++)
        {
            p[i].cnt ++;//記錄這個元素的個數
        }
        p[++k] = p[i];
        i = j-1;
    }
    cdq(1,k);
    memset(ans,0,sizeof(ans));
    for(i = 1; i<= k; i++)
    {
        ans[p[i].sum+p[i].cnt-1] += p[i].cnt;
    }
    for(i = 0; i< n; i++)
    {
        printf("%d\n",ans[i]);
    }

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章