zoukankan      html  css  js  c++  java
  • caioj1097: [视频]树状数组1(快速求和计算) cdq分治入门

    这题虽然是个树状数组,但是也可以用cdq分治做啊~~,这个就是一个浅显的二维偏序的应用?

    cdq分治和普通的分治有什么区别?

    举个栗子:有4个小朋友,你请他们吃饭,假如你分治搞,就会分成很多子问题——1~1号小朋友有多少个来,2~2号小朋友有多少个来,然后程序就会回溯,你就知道1~2号小朋友有多少个来,最后你就知道1~4号小朋友有多少个来了。

    而cdq分治呢?同样是4个小朋友,但是要照顾小朋友的心情,第i号小朋友的开心程度是1~i-1号小朋友有多少个来,你想知道小朋友们的心情,有可能心情不好就不来了,那先往左右搜,然后要把心情的影响加上。可能这个栗子不是很贴切,但是我想说的就是cdq分治中,前面的结果会影响后面的,而且,这个算法做题只能离线。

    那么,我是拿了这题水题来理解。

    俩操作,一个单点修改,一个询问区间和。

    那么我们还是照样按前缀和的做法,把询问分成求1~l-1和1~r。

    那么离线做,按照输入的顺序放进结构体,这个时候你一定发现了,对于一个询问,对它有影响的修改,就是在它前面操作的,并且修改位置也在它询问位置前面的。那么,实际上这个结构体已经是按照操作的顺序排好了,那么要解决的就是位置的问题。具体的做法,就是按照它的位置,做一次归并排序。

    具体怎么做呢,首先先把区间分成l~mid和mid+1~r,当前我们要维护的,就是mid+1~r的全部询问,要先让两边都递归下去,令l~mid的询问解决,以及mid+1~r里的修改施加影响。

    那么在归并的过程中,记录一个sum,表示左边已经l~当前归并到的位置的修改值的和,然后当遇到右边的询问,就将影响释放下去,一直这样做下去,当按x排好序了,对于mid+1~r中的询问,l~r的全部影响都已经解决,最后回溯接受更前面的影响,或者去影响后面的其他询问(你这样归排岂不是把一开始操作的顺序打乱了!?不用担心,l~mid的输入顺序每一个都是比mid+1~r大的,l~mid的顺序改变并不会影响后面的修改

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    int n,m;
    struct node
    {
        int x,tp;LL v;
        //tp=1表示这个是修改操作,x表示修改哪个位置,v表示要加上的值
        //tp=2,3表示这个是问1~x的前缀和,v表示这个影响第几个答案 
    }a[210000],t[210000];int len=0;
    void ins(int x,int tp,int v)
    {
        len++;
        a[len].x=x;a[len].tp=tp;a[len].v=v;
    }
    LL ans[210000];int ansl=0;//答案数组
    bool check(node n1,node n2)
    {
        if(n1.x<n2.x||(n1.x==n2.x&&n1.tp<n2.tp))return true;
        return false;
    }
    void cdq(int l,int r)
    {
        if(l==r)return ;
        int mid=(l+r)/2;
        cdq(l,mid);cdq(mid+1,r);
        
        LL sum=0;//sum表示l~t[p].x的修改的和
        int i=l,j=mid+1,p=l;
        while(i<=mid&&j<=r)
        {
            if(check(a[i],a[j])==true)//只统计左边区间内的修改值,因为右边的修改值已经在递归里影响过了 
            {
                if(a[i].tp==1)sum+=a[i].v;
                t[p++]=a[i++];
            }
            else//将左边的影响影响右边 
            {
                     if(a[j].tp==2)ans[a[j].v]-=sum;
                else if(a[j].tp==3)ans[a[j].v]+=sum;
                t[p++]=a[j++];
            }
        }
        while(i<=mid)t[p++]=a[i++];
        while(j<=r)
        {
                 if(a[j].tp==2)ans[a[j].v]-=sum;
            else if(a[j].tp==3)ans[a[j].v]+=sum;
            t[p++]=a[j++];
        }
        
        for(int i=l;i<=r;i++)a[i]=t[i];
    }
    
    char ss[10];
    int main()
    {
        int x,l,r;LL v;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        { 
            scanf("%s",ss+1);
            if(ss[1]=='C')
            {
                scanf("%d%lld",&x,&v);
                ins(x,1,v);
            }
            else//利用前缀和的思想,把查询操作分为两部分
            {
                scanf("%d%d",&l,&r);
                ansl++;ins(l-1,2,ansl);ins(r,3,ansl);
            }
        }
        cdq(1,len);
        for(int i=1;i<=ansl;i++)printf("%lld
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    洛谷P2345 奶牛集会
    洛谷P3531 [POI2012]LIT-Letters
    codevs 4163 hzwer与逆序对
    各种读入方式速度比较
    洛谷P1420 最长连号
    TCPDump:捕获并记录特定协议 / 端口
    linux下抓取网页快照
    Pro Android 4 第五章 理解Intent
    UpdatePanel和jQuery不兼容
    RAC 11.2.0.4 安装 遇到 INS-06001
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8017372.html
Copyright © 2011-2022 走看看