zoukankan      html  css  js  c++  java
  • [学习笔记] CDQ分治 从感性理解到彻底晕菜

    ==== €€£ WARNING ====

    这篇博文由于过于久远并没有什么干货已被废弃

    新博文链接->CDQ分治&整体二分

    ====                          ====

    最近学了一种叫做CDQ分治的东西...用于离线处理一系列操作与查询似乎跑得很快233

    CDQ的名称似乎源于金牌选手陈丹琦

    概述:

    对于一坨操作和询问,分成两半,单独处理左半边和处理左半边对于右半边的影响,就叫$CDQ$分治。 

    乍一看似乎不算难理解...?

    这"一坨操作和询问"是要求靠左的操作可以影响所有右侧操作,靠右的查询的值依赖于左侧的操作...

    内部实现:

    将左右区间按一定规律排序后分开处理,递归到底时直接计算答案,对于一个区间,按照第二关键字split成两个区间,先处理左区间,之后因为整个区间是有序的,就可以根据左区间来推算右区间的答案,最后递归处理右区间即可。归纳起来就是 
    1. 区间按第一关键字分成两半
    2. 计算左区间对右区间的贡献 
    3. 撤销修改
    4. 按第二关键字拆成两半并排序
    5. 递归下去继续处理

    这种时候常常只能选择参考代码感性理解一下(雾)

    例题-Mokia

    对于上面的例题($Mokia$)来说,我们先将一个查询操作差分为$4$个前缀和分别计算,然后将所有操作按$x$值为第一关键字,$y$为第二关键字排序(保证左边的操作可以影响右边操作),然后按照时间戳分开重新排序为两个序列并分开递归下去求值QwQ

    直接拿这个板子题的实现细节举个栗子好了QwQ

    我们拿$CDQ$函数来说一下...

     1 void CDQ(int l,int r){
     2     if(l==r)
     3         return;
     4     int mid=(l+r)>>1;
     5     int ll=l;
     6     int lr=mid+1;
     7     for(int i=l;i<=r;i++){
     8         if(query[i].ID<=mid&&query[i].operation==0)
     9             Add(query[i].y,query[i].value);
    10         if(query[i].ID>mid&&query[i].operation==1)
    11             ans[query[i].position]+=query[i].value*Query(query[i].y);
    12     }
    13     for(int i=l;i<=r;i++){
    14         if(query[i].ID<=mid&&query[i].operation==0)
    15             Add(query[i].y,-query[i].value);
    16     }
    17     for(int i=l;i<=r;i++){
    18         if(query[i].ID<=mid)
    19             tmp[ll++]=query[i];
    20         else
    21             tmp[lr++]=query[i];
    22     }
    23     for(int i=l;i<=r;i++)
    24         query[i]=tmp[i];
    25     CDQ(l,mid);
    26     CDQ(mid+1,r);
    27 }

    $2 ext{~}6$行没啥可讲的(吧)

    然后我们从$l$到$r$进行遍历.因为我们按$x$和$y$排序了所以更改肯定在它所影响的查询操作的值计算之前进行($7 ext{~}12$行)

    接着我们撤销修改,因为递归下去后这些值会失效所以要清空($13 ext{~}16$行)

    然后我们按照时间戳分别分为左右两部分($17 ext{~}24$行)

    最后递归下去处理.

    仔细分析我们可以发现这个过程刚好做到了"不重不漏":不重复计算查询涉及到的修改操作的贡献;不漏掉修改操作对后面查询的贡献.

    然后摘一句总结

    CDQ分治主要用于处理能够离线的低维偏序(3维及以下),3维偏序常态是套BIT,一般对于x排序,然后对于id进行cdq分治,对于y用BIT来维护即可。 

     据说更高维的偏序也可以处理但是好像需要一些特殊方法?

    (然后又草率地结束了)

    (我好菜啊QwQ)

    (放图跑)

  • 相关阅读:
    python生成随机整数
    pycharm怎么修改python路径
    Linux 在 TOP 命令中切换内存的显示单位
    MySQL之limit使用
    Fiddler设置抓取FireFox火狐的包
    火狐FireFox看视频不能全屏显示的问题
    【.Net】exe加密/加壳工具.Net Reactor
    【WPF】使用控件MediaElement播放视频
    【WPF】在MenuItem中下划线“_”显示不正常
    【.Net】Thread.Start()与ThreadPool.QueueUserWorkItem()的区别
  • 原文地址:https://www.cnblogs.com/rvalue/p/7214242.html
Copyright © 2011-2022 走看看