博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CDQ分治
阅读量:7135 次
发布时间:2019-06-28

本文共 4989 字,大约阅读时间需要 16 分钟。

一、关于CDQ分治

现在给你很多操作,每次给出\(pos\)以及\(x\),表示\(pos\)位置上的数加上x,然后给出很多询问,每次问\(l\)\(r\)之间的和。

显然这个东西\(O(n)\)是可以解决的。

但是如果操作和询问交叉的话(不用树状数组),就不能用这种方法了。但是可以发现如果一个点在\(i\)的时刻被加了一个数,那么在\(i\)及以后的时刻这个位置都会加上这个数(因为不会存在删除的操作)。

所以可以尝试利用这种不删除的特点。我们考虑一个做法。假设要处理\([l,r]\)之间的操作。我们先处理\([l,\lfloor (l+r)/2 \rfloor]\)之间的操作,再处理\([\lfloor (l+r)/2 \rfloor+1,r]\)之间的操作,再考虑左边对右边的影响。

那这道就可以变成刚开始的情况了。

二、题目

1.Luogu P4390 [BOI2007]Mokia 摩基亚

题意:

有n次操作,每次操作要么给一个二维坐标的点加上一个数,要么询问某个矩形内的数的和。考虑CDQ和差分。

题解:

在合并左右的影响时,用差分的思想。如果求的是\((x1,y1)\)\((x2,y2)\)的和。就是求横坐标在\(1\)\(x1-1\)间纵坐标在\(y1\)\(y2\)的树的和,还横坐标在\(1\)\(x2\)间纵坐标在\(y1\)\(y2\)的树的和。考虑扫描线,把询问拆成两个询问,处理每个询问前把所有横坐标在当前询问之前的点都加入当中,用树状数组或线段数维护即可。

代码:

#include 
#include
#include
#include
#include
#include
using namespace std;const int MAXN = 200000;const int MAXX = 2000000;struct Point { int x, y, w;} b[MAXN + 5];struct Query { int id, flag, x, sy, ey;} c[MAXN + 5 << 1];int ans[MAXN + 5], a[MAXN + 5][5], opt, n;bool cmpb(Point a, Point b) { return a.x < b.x; }bool cmpc(Query a, Query b) { return a.x < b.x; }class BinaryIndexTree { private: int c[MAXX + 5]; void _add(int x, int y) { for (int i = x; i <= MAXX; i += i & -i) c[i] += y; } void _dec(int x, int y) { for (int i = x; i <= MAXX; i += i & -i) c[i] -= y; } int _query(int x) { int ret = 0; for (int i = x; i; i -= i & -i) ret += c[i]; return ret; } public: void add(int x, int y) { _add(x, y); } int query(int x, int y) { return _query(y) - _query(x - 1); } void dec(int x, int y) { _dec(x, y); }} bit;void cdq(int l, int r) { if (l == r) return; int mid = l + r >> 1; cdq(l, mid); cdq(mid + 1, r); int bcnt = 0, ccnt = 0; for (int i = l; i <= mid; ++i) if (a[i][0] == 1) b[++bcnt] = (Point){a[i][1], a[i][2], a[i][3]}; for (int i = mid + 1; i <= r; ++i) if (a[i][0] == 2) { c[++ccnt] = (Query){i, -1, a[i][1] - 1, a[i][2], a[i][4]}; c[++ccnt] = (Query){i, 1, a[i][3], a[i][2], a[i][4]}; } sort(b + 1, b + bcnt + 1, cmpb); sort(c + 1, c + ccnt + 1, cmpc); int bptr = 0; for (int i = 1; i <= ccnt; ++i) { while (bptr < bcnt && b[bptr + 1].x <= c[i].x) { bit.add(b[bptr + 1].y, b[bptr + 1].w); ++bptr; } ans[c[i].id] += c[i].flag * bit.query(c[i].sy, c[i].ey); } while (bptr--) bit.dec(b[bptr + 1].y, b[bptr + 1].w);}int main() { scanf("%d", &opt); while (opt != 3) { if (opt == 1) { a[++n][0] = opt; scanf("%d%d%d", &a[n][1], &a[n][2], &a[n][3]); } else if (opt == 2) { a[++n][0] = opt; scanf("%d%d%d%d", &a[n][1], &a[n][2], &a[n][3], &a[n][4]); } scanf("%d", &opt); } cdq(1, n); for (int i = 1; i <= n; ++i) if (a[i][0] == 2) printf("%d\n", ans[i]); return 0;}

2.Luogu P3810 【模板】三维偏序(陌上花开)

题意:

题目很简洁

题解:

这道题目和上一题其实差不多,我们考虑将一维排序,然后对于每个数只找前面的满足条件的。问题是第一维相同的可能统计不到,所以后统计答案的时候对于每个相同的三元组,答案为最大的那个的值。

代码:

#include 
#include
#include
#include
#include
#include
#include
using namespace std;typedef pair
PII;const int MAXN = 100000;struct Node { int x, y, z; bool operator <(Node rhs) const { return x < rhs.x || x == rhs.x && y < rhs.y || x == rhs.x && y == rhs.y && z < rhs.z; }};struct Flower { int s, c, m;} a[MAXN + 5];struct Point { int c, m;} b[MAXN + 5];struct Query { int id, c, m;} c[MAXN + 5];int n, k, cnt[MAXN + 5], ans[MAXN + 5];map
mapp;bool pntcmp(Point a, Point b) { return a.c < b.c;}bool qrycmp(Query a, Query b) { return a.c < b.c;}bool flwcmp(Flower a, Flower b) { return a.s < b.s || a.s == b.s && a.c < b.c || a.s == b.s && a.c == b.c && a.m < b.m;}class BinaryIndexTree { private: static const int MAXX = 200000; int c[MAXX + 5]; void _add(int x) { for (int i = x; i <= MAXX; i += i & -i) ++c[i]; } void _dec(int x) { for (int i = x; i <= MAXX; i += i & -i) --c[i]; } int _query(int x) { int ret = 0; for (int i = x; i; i -= i & -i) ret += c[i]; return ret; } public: void add(int x) { _add(x); } int query(int x, int y) { return _query(y) - _query(x - 1); } void dec(int x) { _dec(x); }} bit;void cdq(int l, int r) { if (l == r) return; int mid = l + r >> 1; cdq(l, mid); cdq(mid + 1, r); int bcnt = 0, ccnt = 0; for (int i = l; i <= mid; ++i) b[++bcnt] = (Point){a[i].c, a[i].m}; for (int i = mid + 1; i <= r; ++i) c[++ccnt] = (Query){i, a[i].c, a[i].m}; sort(b + 1, b + bcnt + 1, pntcmp); sort(c + 1, c + ccnt + 1, qrycmp); int bptr = 0; for (int i = 1; i <= ccnt; ++i) { while (bptr < bcnt && b[bptr + 1].c <= c[i].c) { bit.add(b[bptr + 1].m); ++bptr; } ans[c[i].id] += bit.query(1, c[i].m); } while (bptr--) bit.dec(b[bptr + 1].m);}int main() { scanf("%d%d", &n, &k); for (int i = 1; i <= n; ++i) scanf("%d%d%d", &a[i].s, &a[i].c, &a[i].m); sort(a + 1, a + n + 1, flwcmp); cdq(1, n); for (int i = 1; i <= n; ++i) mapp[(Node){a[i].s, a[i].c, a[i].m}] = max(mapp[(Node){a[i].s, a[i].c, a[i].m}], ans[i]); for (int i = 1; i <= n; ++i) ++cnt[mapp[(Node){a[i].s, a[i].c, a[i].m}]]; for (int i = 0; i < n; ++i) printf("%d\n", cnt[i]); return 0;}

转载于:https://www.cnblogs.com/herald/p/10065997.html

你可能感兴趣的文章
创业找投资,你要警惕的三种人---情商培养
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
大数据波分传输工程方案设计主要细节
查看>>
Z字形扫描(201412-2)
查看>>
如何确定Windows Server 2012中虚拟机的动态内存可用大小
查看>>
P2327 [SCOI2005]扫雷
查看>>
Hibernate基础实例
查看>>
索引设计规范
查看>>
python笔记4:计算输入时间为当年的第几天
查看>>
Linux 常用命令集合
查看>>
ARP的应用案例,测试ARP防火墙的主动防御功能;
查看>>
浅谈ipsec
查看>>
我的友情链接
查看>>
新手入门
查看>>
centos下lamp源码安装
查看>>
cinder-volume服务状态为down 解决方法
查看>>
实战:通过建立的会话查看***
查看>>
Ionic CLI 升级到最新版本
查看>>
移动大时代:烽火Exmobi的主打歌
查看>>