zoukankan      html  css  js  c++  java
  • 深谈CDQ分治

      关于CDQ分治我想我自己做过前面的题应该会了这种思想了吧,然后我是真的“会了”。

    我想针对于偏序问题我是会了,我现在只会三维偏序了,脑子都是疼的。

    但是 CDQ分治最主要的还是基于时间方面的分治思想,所以呢,偏序问题没那么重要了。

    关键是分治!分治(敲黑板)不是偏序!

    下面我们再来几道偏序。。。

    这道题呢 暴力修改+n^2求和 肯定炸了,但是细节注意到拿到题先分析爆long long么

    每次都是单点修改所以 2e5*2e3=4e8不会炸呢。

    想一下如果我们把整个矩阵便利一遍 超时 我们生成整个矩阵爆空间。

    所以需要转换问题 针对每个点都是坐标 x,y 以及该操作的时间 t

    为什么是三个元素啊 这不是三维偏序么?但是对于查询呢 一起放里面不就好了。

    这里求一个矩阵的和我们需要将其转换一下,要不然怎么求 

    转换成 大矩阵的和减去2个小矩阵的和+最小矩阵的和不就行了么。解决了问题。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<vector>
    #include<ctime>
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    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*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        x<0?putchar('-'),x=-x:0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(10);return;
    }
    const int MAXN=800002;
    struct wy
    {
        int x,y,z;
        int v,k;
    }t[MAXN],tmp[MAXN];//三维偏序问题
    int c[MAXN];
    int n,cnt,num,ans[MAXN];
    int cmp(wy x,wy y)
    {
        if(x.x==y.x)
        {
            if(x.y==y.y)return x.v<y.v;
            return x.y<y.y;
        }
        return x.x<y.x;
    }
    int cmp1(wy x,wy y)
    {
        return x.v<y.v;
    }
    void add(int x,int y)
    {
        for(;x<=num;x+=x&(-x))c[x]+=y;
    }
    int ask(int x)
    {
        int cnt=0;
        for(;x;x-=x&(-x))cnt+=c[x];
        return cnt;
    }
    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;
        for(int k=l;k<=r;k++)
        {
            if(j>r||(i<=mid&&t[i].y<=t[j].y))add(t[i].v,t[i].z),tmp[k]=t[i],i++;
            else
            {
                ans[t[j].v]+=ask(t[j].v);
                tmp[k]=t[j];
                j++;
            }
        }
        for(int k=l;k<=mid;k++)add(t[k].v,-t[k].z);
        for(int k=l;k<=r;k++)t[k]=tmp[k];
        return;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();
        while(1)
        {
            int p,x,y,z,u1,u2;
            p=read();
            if(p==3)break;
            ++cnt;
            x=read();y=read();
            if(p==1)
            {
                z=read();
                t[++num].x=x,t[num].y=y,t[num].z=z;
                t[num].v=cnt;
            }
            if(p==2)
            {
                u1=read();u2=read();
                t[++num].x=min(u1-1,x-1);t[num].y=max(u2,y);
                t[num].v=cnt++;t[num].k++;
                t[++num].x=max(u1,x);t[num].y=min(u2-1,y-1);
                t[num].v=cnt++;t[num].k++;
                t[++num].x=min(u1-1,x-1);t[num].y=min(u2-1,y-1);
                t[num].v=cnt++;t[num].k++;
                t[++num].x=max(u1,x);t[num].y=max(u2,y);
                t[num].v=cnt;t[num].k++;
            }
        }
        sort(t+1,t+1+num,cmp);
        //for(int i=1;i<=num;i++)cout<<t[i].x<<' '<<t[i].y<<endl;
        CDQ(1,num);
        sort(t+1,t+1+num,cmp1);
        for(int i=1;i<=num;i++)
        {
            if(t[i].k!=0)
            {
                int xx=ans[t[i].v];
                int yy=ans[t[i+1].v];
                int zz=ans[t[i+2].v];
                int uu=ans[t[i+3].v];
                put(uu-xx-yy+zz);
                i+=3;
            }
        }
        return 0;
    }
    View Code

    关键是思想思想 不是三维偏序!!!(说了是CDQ的思想)

    下面再来一道三维偏序问题:

    这道题呢 很迷的我迷了一晚上加一下午 加一中午。

    听学长讲的博弈论都不想听一直在想如何统计答案。

    时间戳这个我是想出来了,但是三维偏序如何统计答案呢,我迷了一波。

    因为CDQ我光想着CDQ分治左边只会对右边进行累加却没想到啊,这个数字消失之时右边也会对其有价值累加。

    我却一直在被CDQ左边只会对右边有贡献搞乱了,貌似不知道逆序对的性质了。

    哎 惭愧其实我是能想出来的,但是思想一直不在正轨上最后被学长拉回来了。

    这道题其实需要统计两遍然后 左边对右边的贡献和右边对左边的贡献。

    关键是知道自己在写什么数据存到了哪里,哪里是答案 求出来的东西是什么这几点很重要!

    统计两遍很显然吧,然后时间戳相等的将会被累加两次需要减去一次即可。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<vector>
    #include<ctime>
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline long long read()
    {
        long long x=0,f=1;char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    inline void put(long long x)
    {
        x<0?putchar('-'),x=-x:0;
        long long num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(10);return;
    }
    const long long MAXN=100002;
    struct wy
    {
        long long x,y,t;
    }t[MAXN],tmp[MAXN];
    long long n,m,c[MAXN];
    long long q[MAXN],h,num[MAXN],cnt,x,sum[MAXN],pos[MAXN],cnt1;
    long long cmp(wy x,wy y){return x.x>y.x;}
    void add(long long x,long long y){for(;x;x-=x&(-x))c[x]+=y;}
    void add1(long long x,long long y){for(;x<=MAXN;x+=x&(-x))c[x]+=y;}
    long long ans[MAXN];
    long long ask(long long x)
    {
        long long cnt=0;
        for(;x<=MAXN;x+=x&(-x))cnt+=c[x];
        return cnt;
    }
    long long ask1(long long x)
    {
        long long cnt=0;
        for(;x;x-=x&(-x))cnt+=c[x];
        return cnt;
    }
    void CDQ(long long l,long long r)
    {
        if(l==r)return;
        long long mid=(l+r)>>1;
        CDQ(l,mid);
        CDQ(mid+1,r);
        long long i=l,j=mid+1;
        for(long long k=l;k<=r;k++)//左边给右边贡献小t累加大t贡献
        {
            if(j>r||(t[i].t>=t[j].t&&i<=mid))tmp[k]=t[i],add(t[i].y,1),i++;
            else
            {
                sum[t[j].t]+=ask(t[j].y);
                tmp[k]=t[j];
                j++;
            }
        }
        for(long long k=l;k<=mid;k++)add(t[k].y,-1);
        for(long long k=l;k<=r;k++)t[k]=tmp[k];
        return;
    }
    void CDQ1(long long l,long long r)
    {
        if(l==r)return;
        long long mid=(l+r)>>1;
        CDQ1(l,mid);
        CDQ1(mid+1,r);
        long long i=l,j=mid+1;
        for(long long k=l;k<=r;k++)//左边给右边贡献小t累加大t贡献
        {
            if(j>r||(t[i].t>=t[j].t&&i<=mid))tmp[k]=t[i],add1(t[i].y,1),i++;
            else
            {
                sum[t[j].t]+=ask1(t[j].y);
                tmp[k]=t[j];
                j++;
            }
        }
        for(long long k=l;k<=mid;k++)add1(t[k].y,-1);
        for(long long k=l;k<=r;k++)t[k]=tmp[k];
        return;
    }
    void yy()
    {
        for(long long i=h;i>=1;i--)
        {
            cnt1+=ask1(q[i]-1);
            add1(q[i],1);
        }
        return;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(long long i=1;i<=n;i++)
        {
            x=read();
            t[i].x=i;
            t[i].y=x;
            pos[x]=i;
        }
        for(long long i=1;i<=m;i++)x=read(),num[pos[x]]=++cnt;
        for(long long i=1;i<=n;i++)
        {
            if(num[i]!=0)t[i].t=num[i];
            else q[++h]=t[i].y,t[i].t=cnt+1;
        }
        //for(long long i=1;i<=n;i++)cout<<t[i].x<<' '<<t[i].y<<' '<<t[i].t<<endl;
        CDQ(1,n);
        //for(long long i=1;i<=cnt;i++)put(sum[i]);
        sort(t+1,t+1+n,cmp);
        CDQ1(1,n);
        yy();
        //cout<<cnt1<<endl;
        for(long long i=cnt+1;i>=1;i--)ans[i]=sum[i]+ans[i+1];
        for(long long i=1;i<=cnt;i++)put(ans[i]-cnt1);
        return 0;
    }
    View Code

    没有梦想 何必远方?

  • 相关阅读:
    Silerlight 控制datagrid控件多选时不显示详细信息
    正则表达式限制文本框只能输入数字,小数点,英文字母,汉字
    图片正则表达式
    css最小高度,最大高度important
    让网页变灰色兼容各种浏览器
    edecms v5.7模块管理列表为空没有内容
    统一日志的记录格式,用宏调用printf
    出差
    使窗体在指定窗口的顶层
    C BNF grammar
  • 原文地址:https://www.cnblogs.com/chdy/p/10442775.html
Copyright © 2011-2022 走看看