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

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

关于CDQ分治,首先需要明白分治的复杂度。

T(n) = 2T(n/2)+O(kn), T(n) = O(knlogn)

T(n) = 2T(n/2)+O(knlogn), T(n) = O(knlog^2n)

T(n) = 2T(n/2)+O(k), T(n) = O(kn)

那么我们要处理[l, r]内的询问,我们可以分别处理[l, m]和[m+1, r]的询问,然后以较小的复杂度计算出[l, m]对[m+1, r]的贡献。

最简单的cdq就是三维偏序问题。

 

两点(x1, y1, z1)和(x2, y2, z2),同时满足x1 < x2, y1 < y2, z1 < z2,则前面的点小于后面的点。

首先按第一维x排序。

则处理的问题变成对于排在前面的点,统计多少个点满足y维与z维同时小于该点。

CDQ分治。

假设已处理出[l, m]与[m+1, r]。对于[m+1, r]内的所有点,我们还要统计[l, m]内有多少个点相比它更小。

对[l, r]按y维排序,对z维用树状数组统计。

扫描一遍排序后的[l, r]。

若该点在排序前属于[l, m],树状数组单点修改;否则该点在排序前属于[m+1, r],统计一次。

复杂度为O(nlognlogn)

CDQ分治算法的核心就在于:去掉时间的限制,将所有查询要求发生的时刻同化,化动态修改为静态查询 
(其实对于有些问题来说可以把某一维的限制通过排序看作时间限制然后运用CDQ分治) 
这类分治的特殊性在于分治的左右两部分的合并,作用两部分在合并的时候作用是不同的,比如,通过左半部分的影响来更新右半部分,所以分治开始前都要按照某一个关键字排序,然后利用这个顺序,考虑一个区间[l, r]的两部分间的影响。

框架为

void cdq(int l, int r){    if(l == r) return ;    int m = (l+r)/2;    cdq(l, m);    cdq(m+1, r);    //统计[l, m]对[m+1, r]的贡献。整体排序后统计。    sort(pp+l, pp+r+1, yzx);    for(int i = l; i <= r; i++)        if(pp[i].x <= m)            add(pp[i].z, 1);        else            ans[ pp[i].n ] += sum(pp[i].z);    for(int i = l; i <= r; i++)        if(pp[i].x <= m)            add(pp[i].z, -1);}

 

题意:一个人的魅力值是相对于周围人来说的,如果他的颜值,内涵和智慧值同时不低于另外一个人,那么他的魅力值就会加1,给你一些人的颜值,内涵,和智慧值,请输出这些人的魅力值。

1 #include
2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e5+10; 5 struct p{ 6 int n, x, y, z; 7 p(){} 8 p(int n, int x, int y, int z): n(n), x(x), y(y), z(z){} 9 bool operator <(const p& A) const{10 if(x != A.x) return x < A.x;11 return y != A.y? y < A.y: z < A.z;12 }13 bool operator ==(const p& A) const{14 return x == A.x&&y == A.y&&z == A.z;15 }16 };17 bool yzx(p A, p B){
//y z x18 if(A.y != B.y) return A.y < B.y;19 return A.z != B.z? A.z < B.z : A.x < B.x;20 }21 bool cmpn(p A, p B){
//n22 return A.n < B.n;23 }24 p pp[maxn];25 26 int c[maxn], Maxn;27 int lowbit(int x){ return x&-x;}28 int add(int x, int d){29 for(int i = x; i <= Maxn; i += lowbit(i))30 c[i] += d;31 }32 int sum(int x){33 int ret = 0;34 for(int i = x; i; i -= lowbit(i))35 ret += c[i];36 return ret;37 }38 39 int ans[maxn];40 41 void cdq(int l, int r){42 if(l == r) return ;43 int m = (l+r)/2;44 cdq(l, m);45 cdq(m+1, r);46 sort(pp+l, pp+r+1, yzx);47 for(int i = l; i <= r; i++)48 if(pp[i].x <= m)49 add(pp[i].z, 1);50 else51 ans[ pp[i].n ] += sum(pp[i].z);52 for(int i = l; i <= r; i++)53 if(pp[i].x <= m)54 add(pp[i].z, -1);55 }56 57 int same[maxn];// smae[i] 表示 下标为i的ans 与 下标为same[i]相同58 59 int main(){60 int T; scanf("%d", &T);61 while(T--){62 int n;scanf("%d", &n);63 for(int i = 0; i < n ; i++){64 pp[i].n = i;65 scanf("%d%d%d", &pp[i].x, &pp[i].y, &pp[i].z);66 Maxn = max(pp[i].z, Maxn);67 }68 sort(pp, pp+n);//x y z69 70 for(int i = 0; i < n; ){71 int j = i+1;72 while(j < n&&pp[i] == pp[j]) j++;73 while(i < j)74 same[ pp[i++].n ] = pp[j-1].n;75 }76 for(int i = 0; i < n; i++)77 pp[i].x = i;78 79 memset(ans, 0, sizeof(int)*(n+5) );80 cdq(0, n-1);81 82 sort(pp, pp+n, cmpn);83 for(int i = 0; i < n; i++)84 printf("%d\n", ans[ same[ pp[i].n ] ]);85 }86 return 0;87 88 }
View Code

 

转载于:https://www.cnblogs.com/dirge/p/5801335.html

你可能感兴趣的文章
JAXB - Annotations, Annotations for Enums: XmlEnum, XmlEnumValue
查看>>
context 插图
查看>>
文件管理器中不支持的wma歌曲也显示可以播放的音乐图标
查看>>
Java基础学习-流程控制语句
查看>>
Shell中read的常用方式
查看>>
01javascript数据类型
查看>>
asp.net实现md5加密方法详解
查看>>
AJAX
查看>>
table 的thead th 固定 tbody滚动例子
查看>>
并行计算思考----回溯法求解数独问题
查看>>
设计模式:模板模式
查看>>
和菜鸟一起学OK6410之ADC模块
查看>>
代理 模式
查看>>
[git] 细说commit (git add/commit/diff/rm/reset 以及 index 的概念)
查看>>
DOM Core和HTML DOM的区别
查看>>
SurfaceView+MediaPlay的bug们
查看>>
网络表示学习总结
查看>>
完成评论功能
查看>>
far和near
查看>>
Python爬虫实战四之抓取淘宝MM照片
查看>>