关于【CDQ分治】的学习
听娜姐讲完FFT,一脸懵逼,还是来讲讲【CDQ分治】吧。。。
用途:
解决 “带时间轴的更改和查询” 问题。
算法流程:
首先我们要知道,这个算法是离线的,还是利用递归进行求解的。
- 把读入的n个操作都按照时间轴排列好。
- 把时间轴劈开,分为[l,mid]和[mid+1,r]两部分。
- 开始当前层cdq(l,r)的求解前先进行cdq(l,mid)与cdq(mid+1,r)的求解。
- 拎出区间[l,mid]内的所有修改操作和区间[mid+1,r]内的所有查询操作[mid+1,r]。
- 统计区间[l,mid]内的所有修改操作对区间[mid+1,r]内的所有查询操作的影响,并将影响加入ans数组中。
关于算法的正确性:
为什么这么做会是对的呢?我们不妨举个例子来看看。
加入一共有7个时刻(或者说是个7操作),对于位于3时刻的修改操作,在cdq(1,7)中,统计了它对于区间[5,7]中查询的影响,又在cdq(3,4)中统计了区间[4,4]中查询的影响。
可以看到,对于位于3时刻的查询操作,在我们的cdq过程中,统计了它对于[4,7]的时刻中,所有查询操作的影响。
例题以及题解:
例题:
BOI 2007 【Mokia 摩基亚】 洛谷里有,P4390。
题目概述:
(至于为什么是概述呢?——题目B话太TM多了!!!
给你一个二维平面直角坐标系,还有一些操作。
操作有两种:
1.格式"(1,x,y,w)",表示在(x,y)的地方加上权值w。
2.格式"(2,sx,sy,ex,ey)",表示询问以(sx,sy)为左上角顶点,(ex,ey)为右下角顶点,询问矩形区间内的权值和。
后面的修改操作不会对前面的查询操作产生影响。
数据:操作数<=200000,x,y,sx,sy,ex,ey<=2000000
思路分析:
大家还是先打消要用二维树状数组的念头吧
是二维的,那么我们应该怎么做呢?(先提示下吧,log2的,大家可以先想一想)
滴,滴,滴,滴————————
好,时间到,那就再给大家一个提示吧。
某名Niro**的dalao(他/她 真的是dalao)说过:“CDQ分治就是花log n的时间,把所有的修改操作都移到查询操作之前。”
再想想。。。。。。
(假如说还没有想到的话,可以先看一下下文中那些大号加粗的字,看看有没有思路啥的)
(想到了的话,就可以把这篇博客关掉了,再顺手点个推荐啥的)
嗯,现在就到我讲了吧!
二维的,又不能用二维树状数组,再看看博客标题——“CDQ分治”。
en~~~~~
那就肯定是CDQ分治啦!!!
那么当我们把所有的修改都放在查询后面之后,我们应该怎么做呢?
显然要对问题进行“降维打击”。
这个降维打击是个啥呢?——就是把1、2操作(其中把2操作变成起始和结束的两个点)对于x轴进行排序嘛。
排序之后,我们就可以保证在x轴上,前面做过的修改操作,在x轴上是永远包含于后面的查询操作的(如果它的x坐标大于当前查询操作右端点对应的左端点的)。
那么我们只要维护y轴就可以了,这个可以用树状数组来维护。
具体方法的话就是,给树状数组中修改点的y坐标加上它的权值,然后遇到查询操作的右端点时,就统计一下y取值范围内的和就可以了。
那么最后的一个问题就是如果修改点的x坐标小于查询当前查询操作右端点对应的左端点我们应该怎么办呢?
大家先思考一下吧。
......
~~~好了吗?我说喽。——差分嘛!
具体方法就是——遇到左端点时,先把当前树状数组中属于询问范围的y的区间和给减掉嘛。
代码实现:
#include<bits/stdc++.h> using namespace std; const int N=200005; struct point{int x,y,id; }; point a[N],b[N<<1]; int x[N],y[N],sx[N],sy[N],ex[N],ey[N],w[N],ans[N],c[2000005],acnt,bcnt,tot,opt; bool cmp (point a,point b){return a.x<b.x; } void update(int x,int val){if (x<=2000000) c[x]+=val,update(x+(x&(-x)),val); } int query(int x){if (x>0) return c[x]+query(x-(x&(-x))); else return 0; } void cdq(int l,int r){if (l==r) return;int mid=l+r>>1; cdq(l,mid); cdq(mid+1,r);acnt=0,bcnt=0;for (int i=l;i<=mid;i++)if (x[i]>0) ++acnt,a[acnt].x=x[i],a[acnt].y=y[i],a[acnt].id=i;for (int i=mid+1;i<=r;i++)if (sx[i]>0) ++bcnt,b[bcnt].x=sx[i]-1,b[bcnt].y=sy[i],b[bcnt].id=i,++bcnt,b[bcnt].x=ex[i],b[bcnt].y=ey[i],b[bcnt].id=i;sort(a+1,a+1+acnt,cmp);sort(b+1,b+1+bcnt,cmp);int i=1,j=1;while (i<=acnt||j<=bcnt)if (j>bcnt||i<=acnt&&a[i].x<=b[j].x) update(a[i].y,w[a[i].id]),++i;else if (b[j].x==sx[b[j].id]-1&&b[j].y==sy[b[j].id]) ans[b[j].id]-=query(ey[b[j].id])-query(b[j].y-1),j++;else ans[b[j].id]+=query(b[j].y)-query(sy[b[j].id]-1),j++;for (int i=l;i<=mid;i++) if (x[i]>0) update(y[i],-w[i]); } int main(){scanf("0 %d",&w[0]);scanf("%d",&opt);while (opt!=3){if (opt==1) ++tot,scanf("%d%d%d",&x[tot],&y[tot],&w[tot]);else ++tot,scanf("%d%d%d%d",&sx[tot],&sy[tot],&ex[tot],&ey[tot]);scanf("%d",&opt);}cdq(1,tot);for (int i=1;i<=tot;i++)if (sx[i]>0) printf("%d\n",ans[i]);return 0; }
转载于:https://www.cnblogs.com/WR-Eternity/p/10079431.html
关于【CDQ分治】的学习相关推荐
- 【教程】简易CDQ分治教程学习笔记
前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦! CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...
- [偏序关系与CDQ分治]【学习笔记】
组合数学真是太棒了 $CDQ$真是太棒了(雾 参考资料: 1.<组合数学> 2.论文 课件 很容易查到 3.sro __stdcall 偏序关系 关系: 集合$X$上的关系是$X$与$X$ ...
- 简单入门CDQ分治(很有意思的算法)
最近因为牛客暑期多校的一道题涉及到了CDQ分治,于是便去学习了一下CDQ分治. CDQ分治是以曾经的IOI选手陈丹琦命名的一种强大的算法,主要用于解决偏序问题,通过对一维进行排序(在这里说的总维度为二 ...
- [学习笔记]CDQ分治
分治,考虑前一半对后一半的影响. (和一般分治不太相同的思想是,一般分治不分谁对谁的影响,跨mid的都要统计.(全局变量统计) 而CDQ貌似要落脚到前一半对后一半的影响上,也就是贡献在后一半统计,由前 ...
- 【cdq分治】cdq分治与整体二分学习笔记Part2.cdq分治
上午的学习学会了整体二分,下午学了cdq分治 发现了二者的区别: 整体二分的主体是在不断地二分答案(把所有询问二分),而cdq分治则是在不断地二分操作. 当然同样的,cdq分治的复杂度也是与区间长度正 ...
- 【cdq分治】cdq分治与整体二分学习笔记Part1.整体二分
之所以把cdq分治和整体二分放在一起学习,是因为他们两个实在太像了-不管是做法还是代码- 感觉整体二分可能会比cdq分治稍微简单那么一点点?所以先学整体二分. 整体二分是对答案进行二分,其具体操作如下 ...
- CDQ分治学习及例题总结
文章目录 1.**使用cdq分治的条件:** 2.**cdq分治的性质:** 3. **cdq使用步骤:** 4.**自己对cdq分治学习的一些感悟:** 5. cdq分治的详细讲解(转自[stdca ...
- [摸鱼]cdq分治 学习笔记
待我玩会游戏整理下思绪(分明是想摸鱼 cdq分治是一种用于降维和处理对不同子区间有贡献的离线分治算法 对于常见的操作查询题目而言,时间总是有序的,而cdq分治则是耗费\(O(logq)\)的代价使动态 ...
- 学习笔记——CDQ分治
再次感谢这位大佬的博客:https://www.cnblogs.com/ljc20020730/p/10395866.html CDQ分治,是一种在分治合并中计算前面值对后面答案的贡献的一种算法.今天 ...
- cdq分治 学习笔记
什么是 c d q cdq cdq 分治 一种很优美的分治,具体来说,我们解决 [ l , r ] [l,r] [l,r] 这个,跟普通的分治大体思路一样,也是先分治 [ l , m i d ] [l ...
最新文章
- 大专python工资有多高-最新 | 2019年Python工程师的平均薪资是多少?
- boost::geometry::model::segment用法的测试程序
- linux7自带haprox版本,CentOS7.4—构建最新版haproxy高可用群集
- 欢迎光临CAX软件二次开发开源社区!
- ssl1613-最短路径问题【图论,最短路径(还不明显?)】
- java中原始数据文件的输入
- java已被弱化签名,高效Java第四十条建议:谨慎设计方法签名
- Hi3559AV100开发环境搭建
- [转]Hibernate不能自动建表解决办法及Hibernate不同数据库的连接及SQL方言
- win64 oracle下载,oracle 11g 64位下载
- 2021年N1叉车司机最新解析及N1叉车司机模拟考试
- 康托尔三分集是不可列集的证明
- 窃钩者诛,“窃脸”者___?
- element ui 使用导航unique-opened问题
- Selenium||解决给元素输入文本失败问题
- 夕阳美,美到骨子里了
- 2020北大信科计算机考研公示,2020年北京大学信息科学技术学院硕士研究生拟录取名单.pdf...
- 多项式乘积求极值点与拐点“比较快速”的方法:沉鱼落雁闭月羞花
- linux查看网络信息命令
- 使用 x32dbg 分析 PC 上 QQ 撤销功能(好友消息和群消息)