zoukankan      html  css  js  c++  java
  • P3157 [CQOI2011]动态逆序对 CDQ分治

    一道CDQ分治模板题
    简单来说,这道题是三维数点
    对于离线的二维数点,我们再熟悉不过:利用坐标的单调递增性,先按更坐标排序,再按纵坐标排序
    更新和查询时都直接调用纵坐标。
    实际上,我们是通过排序将二维中的一维给消掉了。
    那么,对于题中的三维数点,我们可以先按 $x$ 排序,以 $x$ 为标准进行分治
    在分治的过程中,分别对左右区间按 $y$ 来排序。
    由于左面的 $x$ 坐标一定是小于右面的 $x$ 坐标的。
    所以这一维可以被我们消掉。
    剩下的就是一个二维数点问题了,只需按照顺序依次更新 $z$ 即可。
    (反正左面的 $x$ 比右面小,而且 $y$ 也一定比右面小,只要 $z$ 比右面小是都能统计出来的)

    Code:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout) 
    #define maxn 1000006
    using namespace std;
    int n,m,idx,place[maxn],C[maxn]; 
    long long ans[maxn]; 
    struct BIT{
        int lowbit(int x) { return x&(-x); }
        void add(int pos,int x){ 
            while(pos<=n) C[pos]+=x,pos+=lowbit(pos);  
        } 
        int ask(int pos){
            int sum=0;
            while(pos>0) sum+=C[pos],pos-=lowbit(pos); 
            return sum; 
        }
    }tree;
    struct OPT{
        int x,y,z,rnk,kind,id; 
    }opt[maxn],tmp[maxn]; 
    bool cmp(OPT i,OPT j)
    {
        return (i.x==j.x&&i.y==j.y)?(i.rnk<j.rnk):((i.x==j.x)?i.y<j.y:i.x<j.x);    
    } 
    void solve(int L,int R)
    {
        if(L>=R) return; 
        int mid=(L+R)>>1,tl=L-1,tr=mid; 
        for(int i=L;i<=R;++i){
            if(opt[i].rnk<=mid&&opt[i].kind==1) tree.add(opt[i].y,opt[i].z); 
            if(opt[i].rnk>mid&&opt[i].kind==2)  ans[opt[i].id]+=tree.ask(opt[i].y)*opt[i].z;  
        }
        for(int i=L;i<=R;++i) 
            if(opt[i].rnk<=mid&&opt[i].kind==1) tree.add(opt[i].y,-opt[i].z);
        for(int i=L;i<=R;++i) {
            if(opt[i].rnk<=mid) tmp[++tl]=opt[i];
            else tmp[++tr]=opt[i];
        }
        for(int i=L;i<=R;++i) opt[i]=tmp[i]; 
        solve(L,mid),solve(mid+1,R); 
    }
    int main(){
        //setIO("input");
        scanf("%d%d",&n,&m);
        for(int i=1,a;i<=n;++i)
        {
            scanf("%d",&a);
            opt[++idx].x=i;
            opt[idx].y=a;
            opt[idx].z=1;
            opt[idx].kind=1;
            opt[idx].rnk=idx; 
            place[a]=i; 
            tree.add(a,1); 
            ans[1]+=i-tree.ask(a); 
        }
        for(int i=1;i<=n;++i) tree.add(i,-1); 
        for(int i=1,a;i<=m;++i){
            scanf("%d",&a);
            opt[++idx].x=place[a];
            opt[idx].y=n;
            opt[idx].z=-1;
            opt[idx].kind=2;
            opt[idx].rnk=idx;
            opt[idx].id=i+1;
    
            opt[++idx].x=n;
            opt[idx].y=a;
            opt[idx].z=-1;
            opt[idx].kind=2;
            opt[idx].rnk=idx;
            opt[idx].id=i+1;
    
            opt[++idx].x=place[a];
            opt[idx].y=a;
            opt[idx].z=2;
            opt[idx].kind=2;
            opt[idx].rnk=idx;
            opt[idx].id=i+1; 
    
            opt[++idx].x=place[a];
            opt[idx].y=a;
            opt[idx].z=-1;
            opt[idx].kind=1; 
            opt[idx].rnk=idx;
        }
        sort(opt+1,opt+1+idx,cmp); 
        solve(1,idx); 
        for(int i=2;i<=m;++i) ans[i]+=ans[i-1]; 
        for(int i=1;i<=m;++i) printf("%lld
    ",ans[i]); 
        return 0; 
    }
    

      

  • 相关阅读:
    java 的 线程池应用和实践
    拦截信息短信息并转发到指定手机
    分享 UC优视 的android程序员面试题
    解释通讯协议中的xml
    设计模式工厂模式
    MongoDB基础教程系列第一篇 进入MongoDB世界
    Docx组件读写Word文档介绍
    [转]Oracle数据库逻辑增量备份之exp/imp
    JSON文件读取
    JAVA综合--如何掌握JDK1.5枚举类型[转]
  • 原文地址:https://www.cnblogs.com/guangheli/p/10257009.html
Copyright © 2011-2022 走看看