【算法】CDQ分治 -- 三维偏序 & 动态逆序对
初次接触CDQ分治,感觉真的挺厉害的。整体思路即分而治之,再用之前处理出来的答案统计之后的答案。
大概流程是(对于区间 l ~ r):
1.处理 l ~mid, mid + 1 ~ r 的答案;
2.分别排序规整;
3.计算 l ~ mid 中每一个数对 mid + 1 ~ r 中的答案的贡献, 累加;
4.得到区间l ~ r的答案。
CDQ分治我一共也才做了两道题目, 就一起整理在这里了。大体都差不多,CDQ+树状数组分别维护两个维度。
1.三维偏序
- #include <bits/stdc++.h>
- using namespace std;
- #define maxn 3000000
- #define lowbit(x) x &(-x)
- int n, k, tot, ans[maxn], c[maxn];
- struct node
- {
- int a, b, c, ans, cnt;
- }num[maxn], a[maxn];
- int read()
- {
- int x = , k = ;
- char c;
- c = getchar();
- while(c < '' || c > '') { if(c == '-') k = -; c = getchar();}
- while(c >= '' && c <= '') x = x * + c - '', c = getchar();
- return x * k;
- }
- bool cmp(node a, node b)
- {
- if(a.a != b.a) return a.a < b.a;
- if(a.b != b.b) return a.b < b.b;
- return a.c < b.c;
- }
- bool cmp2(node a, node b)
- {
- if(a.b != b.b) return a.b < b.b;
- return a.c < b.c;
- }
- void Update(int x, int v)
- {
- for(int i = x; i <= k; i += lowbit(i))
- c[i] += v;
- }
- int Query(int x)
- {
- int ans = ;
- for(int i = x; i; i -= lowbit(i))
- ans += c[i];
- return ans;
- }
- void cdq(int l, int r)
- {
- int mid = (l + r) >> ;
- if(r - l >= ) cdq(l, mid), cdq(mid + , r);
- if(r == l) return;
- sort(num + l, num + mid + , cmp2);
- sort(num + mid + , num + r + , cmp2);
- int i = l, j = mid + ;
- while(i <= mid && j <= r)
- {
- if(num[i].b <= num[j].b) Update(num[i].c, num[i].cnt), i ++;
- else num[j].ans += Query(num[j].c), j ++;
- }
- while(i <= mid) Update(num[i].c, num[i].cnt), i ++;
- while(j <= r) num[j].ans += Query(num[j].c), j ++;
- for(int i = l; i <= mid; i ++) Update(num[i].c, -num[i].cnt);
- }
- int main()
- {
- n = read(), k = read();
- for(int i = ; i <= n; i ++)
- a[i].a = read(), a[i].b = read(), a[i].c = read();
- sort(a + , a + + n, cmp);
- for(int i = ; i <= n;)
- {
- int j = ;
- while(i + j <= n && a[i].a == a[i + j].a && a[i].b == a[i + j].b && a[i].c == a[i + j].c) j ++;
- num[++ tot] = a[i];
- num[tot].cnt = j;
- i += j;
- }
- cdq(, tot);
- for(int i = ; i <= tot; i ++) ans[num[i].ans + num[i].cnt - ] += num[i].cnt;
- for(int i = ; i < n; i ++) printf("%d\n", ans[i]);
- return ;
- }
2.动态逆序对
- #include <bits/stdc++.h>
- using namespace std;
- #define maxn 2000000
- #define ll long long
- #define lowbit(x) x & (-x)
- int n, m, timer, a[maxn], b[maxn], d[maxn], t[maxn];
- ll ans[maxn], c[maxn];
- struct node
- {
- int t, num, pl;
- ll ans;
- }w[maxn];
- int read()
- {
- int x = , k = ;
- char c;
- c = getchar();
- while(c < '' || c > '') { if(c == '-') k = -; c = getchar();}
- while(c >= '' && c <= '') x = x * + c - '', c = getchar();
- return x * k;
- }
- bool cmp(node a, node b)
- {
- if(a.t != b.t) return a.t < b.t;
- else return a.pl < b.pl;
- }
- bool cmp2(node a, node b)
- {
- return a.pl < b.pl;
- }
- bool cmp3(node a, node b)
- {
- return a.pl > b.pl;
- }
- void add(int x, int num)
- {
- for(int i = x; i <= n; i += lowbit(i))
- c[i] += num;
- }
- ll query(int x)
- {
- ll ans = ;
- for(int i = x; i; i -= lowbit(i))
- ans += c[i];
- return ans;
- }
- void CDQ(int l, int r)//位置在我之前,num>我的
- {
- int mid = (l + r) >> ;
- if(r - l >= ) CDQ(l, mid), CDQ(mid + , r);
- if(l == r) return;
- sort(w + l, w + + mid, cmp2);
- sort(w + mid + , w + r + , cmp2);
- int i = l, j = mid + ;
- while(i <= mid && j <= r)
- {
- if(w[i].pl < w[j].pl) add(w[i].num, ), i ++;
- else w[j].ans += (query(n) - query(w[j].num)), j ++;
- }
- while(i <= mid) add(w[i].num, ), i ++;
- while(j <= r) w[j].ans += (query(n) - query(w[j].num)), j ++;
- for(int i = l; i <= mid; i ++)
- add(w[i].num, -);
- }
- void CDQ2(int l, int r)//位置在我之后,num<我的
- {
- int mid = (l + r) >> ;
- if(r - l >= ) CDQ2(l, mid), CDQ2(mid + , r);
- if(l == r) return;
- sort(w + l, w + + mid, cmp3);
- sort(w + mid + , w + r + , cmp3);
- int i = l, j = mid + ;
- while(i <= mid && j <= r)
- {
- if(w[i].pl > w[j].pl) add(w[i].num, ), i ++;
- else w[j].ans += (query(w[j].num)), j ++;
- }
- while(i <= mid) add(w[i].num, ), i ++;
- while(j <= r) w[j].ans += (query(w[j].num)), j ++;
- for(int i = l; i <= mid; i ++)
- add(w[i].num, -);
- }
- int main()
- {
- n = read(), m = read();
- for(int i = ; i <= n; i ++)
- {
- a[i] = read();
- b[a[i]] = i;
- }
- timer = m;
- for(int i = ; i <= m; i ++)
- {
- d[i] = read();
- t[b[d[i]]] = timer --;
- }
- for(int i = ; i <= n; i ++) w[i].t = t[i], w[i].num = a[i], w[i].pl = i;
- sort(w + , w + + n, cmp);
- CDQ(, n);
- for(int i = ; i <= n; i ++) ans[w[i].t] += w[i].ans;
- for(int i = ; i <= n; i ++) w[i].t = t[i], w[i].num = a[i], w[i].pl = i, w[i].ans = ;
- sort(w + , w + + n, cmp);
- memset(c, , sizeof(c));
- CDQ2(, n);
- for(int i = ; i <= n; i ++) ans[w[i].t] += w[i].ans;
- for(int i = ; i <= m; i ++) ans[i] += ans[i - ];
- for(int i = m; i >= ; i --) printf("%lld\n", ans[i]);
- return ;
- }
【算法】CDQ分治 -- 三维偏序 & 动态逆序对的更多相关文章
- cdq分治·三维偏序问题
转载自FlashHu大佬的博客CDQ分治总结(CDQ,树状数组,归并排序),在讲述部分有部分删改,用了自己的代码 CDQ分治的思想 CDQ分治是基于时间的离线分治算法.这一类分治有一个重要的思想——用 ...
- BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]
Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...
- 洛谷P3810 陌上花开 CDQ分治(三维偏序)
好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...
- NEUOJ 1702:撩妹全靠魅力值(CDQ分治三维偏序)
http://acm.neu.edu.cn/hustoj/problem.php?id=1702 思路:三维偏序模板题,用CDQ分治+树状数组或者树套树.对于三元组(x,y,z),先对x进行排序,然后 ...
- BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)
题意 略- 分析 就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]f[i ...
- CDQ分治 三维偏序
这应该是一道CDQ分治的入门题目 我们知道,二维度的偏序问题直接通过,树状数组就可以实现了,但是三维如何实现呢? 我记得以前了解过一个小故事,应该就是分治的. 一个皇帝,想给部下分配任务,但是部下太多 ...
- BZOJ.1935.[SHOI2007]Tree园丁的烦恼(CDQ分治 三维偏序)
题目链接 矩形查询可以拆成四个点的前缀和查询(树套树显然 但是空间不够) 每个操作表示为(t,x,y),t默认有序,对x分治,y用树状数组维护 初始赋值需要靠修改操作实现. //119964kb 43 ...
- BZOJ.3262.陌上花开([模板]CDQ分治 三维偏序)
题目链接 BZOJ3262 洛谷P3810 /* 5904kb 872ms 对于相邻x,y,z相同的元素要进行去重,并记录次数算入贡献(它们之间产生的答案是一样的,但不去重会..) */ #inclu ...
- BZOJ - 1935 / 1176 cdq分治 三维偏序
题意:给定n*m的网格,且给出n个(x,y)表示该网格已被占有,q次询问(x1,y1)到(x2,y2)的网格中有多少个被占有,n,m范围1e7,q范围5e5 cdq按x轴排序,树状数组维护y轴 #in ...
随机推荐
- jQuery获取data-*属性值
下面就详细介绍四种方法获取data-*属性的值 <li id="getId" data-id="122" data-vice-id="11&qu ...
- springcloud生态图
springcloud生态图
- Hadoop(13)-MapReduce框架原理--Job提交源码和切片源码解析
1.MapReduce的数据流 1) Input -> Mapper阶段 这一阶段的主要分工就是将文件切片和把文件转成K,V对 输入源是一个文件,经过InputFormat之后,到了Mapper ...
- Node.js中的不安全跳转如何防御详解
Node.js中的不安全跳转如何防御详解 导语: 早年在浏览器大战期间,有远见的Chrome认为要运行现代Web应用,浏览器必须有一个性能非常强劲的Java引擎,于是Google自己开发了一个高性能的 ...
- vue---day04
1. Node.js 1.1 介绍: - Node.js 是一个JavaScript运行环境,实质上是对Chrome V8引擎的封装. - Node.js 不是一个 JavaScript 框架,不同于 ...
- Educational Codeforces Round 47 (Rated for Div. 2) :B. Minimum Ternary String
题目链接:http://codeforces.com/contest/1009/problem/B 解题心得: 题意就是给你一个只包含012三个字符的字符串,位置并且逻辑相邻的字符可以相互交换位置,就 ...
- [Cracking the Coding Interview] 4.3 List of Depths
Given a binary tree, design an algorithm which creates a linked list of all the nodes at each depth. ...
- SapScript
* [OPEN_FORM] SAPscript: フォーム印刷の開始 * [START_FORM] SAPscript: 書式を開始 * [WRITE_FORM] SAPscript: 書式ウィンドウ ...
- 教你如何更改xshell中的转发规则
使用不同的类型转发,与之对应的端口,所以如果想要使用不同类型的转发就要更改端口使其与之一一对应.本集xshell专栏文章将为大家讲解如何更改转发规则. 更改转发规则操作如下: 1.打开会话对话框. 2 ...
- 关于springboot 打包问题 jar包和 war包
起因:项目开发完成 需要打包部署了 发现自己不会打包 那么开始网上学习打包? 那么怎么来打包那? 我们以前没有采用springboot 时候我们都是直接将项目打成war包形式 然后放到tomc ...