cdq分治(bzoj 1176: [Balkan2007]Mokia && bzoj 2683: 简单题)

来源:互联网 发布:java bigdecimal取整 编辑:程序博客网 时间:2024/06/06 02:38

CDQ分治:

本质:对询问进行分治

优点:和莫队分块一样都属于技巧,关键时刻能免去复杂的数据结构,常数小

缺点:必须离线

参考:http://blog.csdn.net/hbhcy98/article/details/50642773

http://www.cnblogs.com/mlystdcall/p/6219421.html


问题提出:

假设有数十万个操作,每次可以是修改和查询,可以这样理解:

对于第x个查询,只有前面的部分操作会对该查询有影响,而部分操作没有影响,

例如一个空的坐标系,操作C(x, y)表示添加一个点(x, y),Q(x, y)表示查询在(0, 0)到(x, y)这个范围内有多少个点

那么C(1, 2)会让Q(3, 5)的答案+1,C(4, 1)却对Q(3, 5)没有影响

这样每次查询的答案相当于之前若干次操作的叠加!


思考:

那么理论上只要对于每个询问,只要知道有多少个操作对它有贡献就行了,

而很容易发现,很好判定一个操作是否对某次查询有贡献,就像上面坐标系的例子:

对于C(x, y)和Q(x', y'),①满足x<=x'就可能有贡献,但只要x>x'就一定不可能有贡献这就相当于是一个“序”

所以可以先将所有的C和Q作为一个整体按x排序

但是不一定,对于C(x, y)和Q(x', y'),还必须满足②y<=y',这就相当于第二个"序",也就是说按x排完序之后前面满足条件y<=y'的C(x, y)的数量才是Q(x', y')的答案,考虑暴力,遇到一个C(x, y)就让cnt[y]++,遇到一个Q(x', y')的话查询cnt[]的前缀和,答案就是∑cnt[i]  (0<=i<=y),这是经典问题,可以用树状数组解决

其实到这里对于先给n个加点操作,再给m个查询操作的问题就可以解决了!

但是万一加点操作和查询操作(也就是C和Q)混在一起呢?这样就相当于有第三个“序”,在满足x<'x'和y<=y'的条件下还要满足这个C出现在这个Q之前!令C(x, y, s)表示在第s秒添加一个点(x, y),Q(x', y', s')表示查询在s'秒之前(0, 0)到(x, y)这个范围内有多少个点,第三维又该如何解决呢?


解决:

这就是“三维偏序问题”,第一维直接排序,第二维可以树状数组,第三维就必须用CDQ分治了

参考题目:bzoj 3262:陌上花开(三维偏序裸题)

当然CDQ分治本质当然还是分治,只不过是对操作和询问的分治,就拿上面例子,大致步骤如下:

①对于所有的C(x, y, s)、Q(x', y', s')当然还是按x排序(y仍然用树状数组暴力)

②假设共有n个操作+查询,开始二分,第一步当然是整个区间[1, n]

③m = (1+n)/2,将整个区间分为左右两个部分,更新y用树状数组就不说了,所有在[1, m]区间内满足s<m的C操作对所有在(m, n]范围内满足s'>m的Q询问有贡献,计算这个贡献,然后重排,在保证x有序的情况下将所有满足s<=m的全部丢在左区间,将所有s>m+1的全部丢在右区间,递归区间[1, m]和(m, n],重复步骤③

④结束,输出答案!


这样问题就解决了,复杂度O(nlog²n)

下面看题


2683: 简单题

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 1565  Solved: 632
[Submit][Status][Discuss]

Description

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

命令

参数限制

内容

1 x y A

1<=x,y<=N,A是正整数

将格子x,y里的数字加上A

2 x1 y1 x2 y2

1<=x1<= x2<=N

1<=y1<= y2<=N

输出x1 y1 x2 y2这个矩形内的数字和

3

终止程序

Input

输入文件第一行一个正整数N。
接下来每行一个操作。

Output

对于每个2操作,输出一个对应的答案。

Sample Input

4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

Sample Output

3
5


没错就是上面例子中的那道题,题解已经给出了

那就看程序吧,可以将每个查询拆成四个(0, 0)到(x, y)的部分


#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int n, t, z, tre[500005], ans[200005];typedef struct Res{int x, y, val, opt, id, xd;bool operator < (const Res &b) const{if(x<b.x || x==b.x && y<b.y || x==b.x && y==b.y && opt<b.opt)return 1;return 0;}}Res;Res s[800005], L[400005], R[400005];void Update(int x, int val){while(x<=n){tre[x] += val;x += x&-x;}}int Query(int x){int ans = 0;while(x){ans += tre[x];x -= x&-x;}return ans;}void Cdq(int l, int r){int m, i, p, q;if(l==r)return;m = (l+r)/2;for(i=l;i<=r;i++){if(s[i].opt==1 && s[i].id<=m)Update(s[i].y, s[i].val);if(s[i].opt==2 && s[i].id>m)ans[s[i].xd] += Query(s[i].y)*s[i].val;}for(i=l;i<=r;i++){if(s[i].opt==1 && s[i].id<=m)Update(s[i].y, -s[i].val);}p = q = 0;for(i=l;i<=r;i++){if(s[i].id<=m)L[++p] = s[i];elseR[++q] = s[i];}for(i=l;i<=m;i++)s[i] = L[i-(l-1)];for(i=m+1;i<=r;i++)s[i] = R[i-m];Cdq(l, m);Cdq(m+1, r);}int main(void){int i, opt, x1, y1, x2, y2;scanf("%d", &n);while(1){scanf("%d", &opt);if(opt==3)break;else if(opt==1){t++;scanf("%d%d%d", &s[t].x, &s[t].y, &s[t].val);s[t].opt = 1, s[t].id = t;}else{z++;scanf("%d%d%d%d", &x1, &y1, &x2, &y2);t++, s[t].x = x1-1, s[t].y = y1-1, s[t].xd = z, s[t].id = t, s[t].val = 1, s[t].opt = 2;t++, s[t].x = x2, s[t].y = y2, s[t].xd = z, s[t].id = t, s[t].val = 1, s[t].opt = 2;t++, s[t].x = x1-1, s[t].y = y2, s[t].xd = z, s[t].id = t, s[t].val = -1, s[t].opt = 2;t++, s[t].x = x2, s[t].y = y1-1, s[t].xd = z, s[t].id = t, s[t].val = -1, s[t].opt = 2;}}sort(s+1, s+t+1);Cdq(1, t);for(i=1;i<=z;i++)printf("%d\n", ans[i]);return 0;}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 月经期吃了芒果怎么办 月经量少又黑怎么办 来月经黑色的血怎么办 月经来的是黑色怎么办 来月经有血块是怎么办 月经又少又黑怎么办 来月经发黑又少怎么办 月经血发黑量少怎么办 做人流后肚子胀怎么办 怀孕见红了肚子不痛怎么办 月经来是黑色的怎么办 怀孕了长了痔疮怎么办 怀孕了有外痔疮怎么办 孕妇长痔疮很痛怎么办 孕9个月尿路感染怎么办 旁边有人尿不出来怎么办 外阴破皮了应该怎么办 脸上长脂肪粒怎么办怎么能消除 挤黑头留下的坑怎么办 长痘留下的坑怎么办 鼻子上留下黑印怎么办 狗狗眼里长息肉怎么办 狗狗眼角长息肉怎么办 脸上长了好多脂肪粒怎么办 脸上毛孔粗大有黑头怎么办 脸颊毛孔粗有黑头怎么办 鼻子上有黑头怎么办小窍门 脸上很多粉刺和油脂粒怎么办 毛孔里都是角栓怎么办 脸上长了很多脂肪粒怎么办 脸上全是油脂粒怎么办 外阴口长了疙瘩怎么办 外阴痒怎么办用什么洗 有子宫内膜增厚怎么办 脸上痘痘特别疼怎么办 眉间和下巴长痘怎么办 眼下方两边长斑怎么办 眼睛下面长斑了怎么办 24岁眼下有细纹怎么办 17岁眼下有细纹怎么办 眼下有细纹怎么办 知乎