zoukankan      html  css  js  c++  java
  • COGS 2479. [HZOI 2016]偏序 [CDQ分治套CDQ分治 四维偏序]

    传送门

    给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足i<j且ai<aj且bi<bj且ci<cj的数对(i,j)的个数。

    对于100%的数据,1<=n<=50000,保证所有的ai、bi、ci分别组成三个1~n的排列。


    $CDQ$分治套$CDQ$分治也不是很难嘛

    对于本题,设四维$a,b,c,d$

    $Sort at a$

    $CDQ(l,r)$

    $quad CDQ(l,mid)$

    $quad CDQ(mid+1,r)$

    $quad Merge_Sort at b$ 每个元素标记属于$[l,mid]or [mid+1,r]$

    $quad CDQ2(l,r)$

    $CDQ2(l,r)$要做的就是按时间序维护一个二维点集$(c,d)$ 加点与询问一个范围内点的个数

    和普通的三维偏序一样,就是多了一个标记的限制(来自$CDQ$中$a$的限制,必须用标记不能判断$a le mid$,因为$CDQ2$是要递归下去的,$mid$就变了)

    有一个时间序$b$和限制$a$,然后$c$归并排序,$d$树状数组维护

    完成啦!

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int N=5e4+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n;
    struct Operation{
        int a,b,c,d;
        bool flag;
    }a[N],t1[N],t2[N];
    int c[N];
    inline int lowbit(int x){return x&-x;}
    inline void add(int p,int v){for(;p<=n;p+=lowbit(p)) c[p]+=v;}
    inline int sum(int p){
        int re=0;
        for(;p;p-=lowbit(p)) re+=c[p];
        return re;
    }
    int ans;
    void CDQ2(int l,int r){
        if(l==r) return;
        int mid=(l+r)>>1;
        CDQ2(l,mid);CDQ2(mid+1,r);
        int i=l,j=mid+1,p=l;
        Operation *a=t1,*t=t2;
        while(i<=mid||j<=r){
            if(j>r||(i<=mid&&a[i].c<a[j].c)){
                if(a[i].flag) add(a[i].d,1);
                t[p++]=a[i++];
            }else{
                if(!a[j].flag) ans+=sum(a[j].d);
                t[p++]=a[j++];
            }
        }
        for(int i=l;i<=mid;i++) if(a[i].flag) add(a[i].d,-1);
        for(int i=l;i<=r;i++) a[i]=t[i];
    }
    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,p=l;
        Operation *t=t1;
        while(i<=mid||j<=r){
            if(j>r||(i<=mid&&a[i].b<a[j].b)) (t[p++]=a[i++]).flag=1;
            else (t[p++]=a[j++]).flag=0;
        }
        for(int i=l;i<=r;i++) a[i]=t[i];
        CDQ2(l,r);
    }
    int main(){
        freopen("partial_order.in","r",stdin);
        freopen("partial_order.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++) a[i].b=read();
        for(int i=1;i<=n;i++) a[i].c=read();
        for(int i=1;i<=n;i++) a[i].d=read(),a[i].a=i;
        CDQ(1,n);
        printf("%d",ans);
    }
  • 相关阅读:
    OFDM系统中频域同步技术及FPGA实现
    SystemVerilog的挑战和机遇
    基础知识要牢固..复习复习,再复习
    样式在.net下测试不成功.附解决办法
    学习.net2.0的网站
    08年又快结束了..抱怨下!~
    今天去面试.net开发,感想
    在b/s开发中经常用到的javaScript技术
    淘宝"新版"首页
    Ajax技术简单入门
  • 原文地址:https://www.cnblogs.com/candy99/p/6442434.html
Copyright © 2011-2022 走看看