码迷,mamicode.com
首页 > 其他好文 > 详细

P3810 【模板】三维偏序(陌上花开)

时间:2018-09-17 14:38:05      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:getchar   结构   ons   mes   数字   ref   数组   span   include   

传送门

CDQ分治

先三关键字排序

然后把第二关键字归并排序

在合并子区间时用 第三关键字的权值树状树组 算出子区间的答案

为什么可以这样搞呢

首先第一维已经有序

所以只要考虑左边对右边的影响

把第二维归并时 左子区间的一二关键字 全部小于 右子区间的一二关键字

所以也只要考虑左边对右边的影响

就用 第三关键字权值树状树组 搞一搞 二维偏序 就好了

二维偏序应该懂吧,实现和细节还是看代码吧

还要注意有重复的数

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
    int x=0; char ch=getchar();
    while(ch<0||ch>9) ch=getchar();
    while(ch>=0&&ch<=9)
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x;
}

const int N=4e5+7;
int n,m;
int a[N],b[N],c[N],p[N],cnt[N],ans[N],v[N];
//a,b,c为三个关键字,p存排序去重后的数据,这里没用结构体,可以省空间
//v是每个数重复的数量
inline bool cmp1(const int &x,const int &y){ return a[x]<a[y]|| (a[x]==a[y]&& (b[x]<b[y]|| (b[x]==b[y]&&c[x]<c[y]) ) ); }
//不用结构体排序的骚操作

int t[N];//数状数组
inline void add(int x,int v)
{
    while(x<=m)
    {
        t[x]+=v;
        x+=x&-x;
    }
}
inline int query(int x)
{
    int res=0;
    while(x)
    {
        res+=t[x];
        x-=x&-x;
    }
    return res;
}

int tmp[N];//归并时的临时数组
void cdq(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    cdq(l,mid); cdq(mid+1,r);//先归并处理子区间

    int i=l,j=mid+1,tot=0;
    while(i<=mid&&j<=r)
    {
        int x=p[i],y=p[j];
        if(b[x]<=b[y]) add(c[x],v[x]),tmp[++tot]=x,i++;
        else cnt[y]+=query(c[y]),tmp[++tot]=y,j++;
    }//核心,树状数组维护二维偏序

    while(j<=r) cnt[p[j]]+=query(c[p[j]]),tmp[++tot]=p[j],j++;
    while(i<=mid) tmp[++tot]=p[i],i++;
    //可能还有一些没处理完

    int mx=b[p[r]];
    for(i=l; i<=mid&&b[p[i]]<=mx ;i++) add(c[p[i]],-v[p[i]]);//用完要这样清空
    for(i=l;i<=r;i++) p[i]=tmp[i-l+1];//归并排序
}

int main()
{
    n=read(); m=read();
    for(int i=1;i<=n;i++)
        p[i]=i,a[i]=read(),b[i]=read(),c[i]=read();

    sort(p+1,p+n+1,cmp1);
    int tot=1;
    for(int i=2;i<=n;i++)
    {
        int x=p[i],y=p[tot];
        v[y]++;
        if(a[x]^a[y]||b[x]^b[y]||c[x]^c[y]) p[++tot]=x;
    }
    v[p[tot]]++;
    //去重并计算重复的数量

    cdq(1,tot);
    for(int i=1;i<=tot;i++) ans[cnt[p[i]]+v[p[i]]-1]+=v[p[i]];//注意有重复的数字
    for(int i=0;i<n;i++) printf("%d\n",ans[i]);
    return 0;
}

 

P3810 【模板】三维偏序(陌上花开)

标签:getchar   结构   ons   mes   数字   ref   数组   span   include   

原文地址:https://www.cnblogs.com/LLTYYC/p/9661831.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!