CDQ分治入门

简介

CDQ分治是一种特别的分治方法,它由CDQ(陈丹琦)神犇于09国家集训队作业中首次提出,因此得名。CDQ分治属于分治的一种。它一般只能处理非强制在线的问题,除此之外这个算法作为某些复杂算法的替代品几乎是没有缺点的。

深入

对于一个数据结构题而言(或者需要运用数据结构的地方),我们无非就是做两件操作,一是修改,二是查询。

对于修改而言,有插入,删除,变更(其实等价于删除再插入)这几种方式。

那么查询的本质是什么呢?我们思考所遇到过的数据结构题,可以发现查询实际上就在做一件事情:把符合本次查询的限制的修改对答案产生的效果合并起来满足。这种限制通常表现为一种序的要求,并且这种序是广义的,符合限制的操作往往是按某种序(或多种序)排序后的操作的前缀。        通常来说,查询一定有时间上的限制,也就是要求考虑发生在某个时刻之前的所有查询,对于一个问题而言,假如所有查询要求的发生时刻相同,那这就是一个静态查询问题,如果要求发生的时刻随着查询而变,那这就是一个动态修改问题,动态修改问题较静态查询而言复杂很多,往往需要高级数据结构,可持久化等手段,而静态查询简单很多,例如时间倒流,twopointers之类的方法都是很好的选择。

  动态修改->静态查询!

CDQ分治算法的核心就在于:去掉时间的限制,将所有查询要求发生的时刻同化,化动态修改为静态查询(其实对于有些问题来说可以把某一维的限制通过排序看作时间限制然后运用CDQ分治)。

  我们记过程Solve(l,r)表示处理完[l,r]内的修改对查询的影响。此时我们引入分治思想,将操作序列划分为[l,mid],[mid+1,r]两个区间,这两个/区间内部的修改对区间内部的查询的影响是完全相同的/的子问题,我们递归处理,处理完之后剩下来只要考虑[l,mid]中的修改对[mid+1,r]中的查询的影响。这时我们发现这其实已经变成了一个静态查询问题,因为所有的查询都发生在修改之后,我们只需要考虑静态查询的问题如何处理即可。

  具体做法

考虑这样一个问题,有若干询问和若干修改,要求在O(nlogn)时间复杂度内回答所有的询问。(下把询问与修改统称为操作)。

  我们把[l,r]代表当前处理的操作的区间,即处理第l个到第r个操作,先找到区间的中间m=(l+r)/2。

    (1)然后对于前一半[l,m]我们先递归解决。

    (2)对于所有在[l,m]内的修改操作,枚举处理它对于[m,r]内的所有操作影响。

    (3)之后递归处理[m,r]这一区间。

  复杂度分析:分治共有log(n)层,那么要求每一层都在线性的时间复杂度内完成,才能保证总时间复杂度是O(nlogn)。

   对于不同的题目,修改和询问是不一样的。在某些修改之间互相独立的题目下,还可以调换(2)(3)的顺序。

  当然cdq分治也可以像其他的分治方法一样,巧妙利用归并排序,来实现每层O(logn)

接下来我们看道题目帮助理解

Arnooks's Defensive Line [Uva live 5871]

Describe  (不想看英语的请往下跳到一句话题意)

  Based on the latest intelligence reports, Chief Arnook of the northern tribe has become suspicious of the warrior nations that dwell south of the border. The chief has ordered his warriors to protect the southern border which runs parallel to the 54 o latitude line and stretches between the longitudes of 1 o to 1000, 000, 000 o , inclusive.
  Each warrior is assigned the task of protecting a segment of the border defined to lie between longitudes a and b, inclusive. No two warriors are assigned to protect the exact same segment. Bound by loyalty to his chief, a warrior will inform the chief upon his arrival at his appointed post and will never leave once he arrives.
  Your task is to write a program that performs the following two operations + a b a warrior assumes his position and protects the segment between longitudes a and b, inclusive. ? c d computes the number of warriors who completely protect the segment between longitudes c and d, inclusive. The segment between the longitudes c and d, inclusive, is said to be completely protected by a warrior X if and only if warrior X protects a segment between a and b, inclusive, and a ≤ c < d ≤ b. to help Chief Arnook track the status of his border protection.

Input
The input starts with an integer N (1 ≤ N ≤ 500000), on a line by itself, that indicates the number of operations. Each of the following N lines contains one operation. The description of an operation consists of a character ‘+’ or ‘?’ followed by two integers on a line by itself. The entries on a line are separated by single blank spaces.

Output
There is one output line for each input line that starts with the operation ‘?’. The output consists of a single integer that represents the number of warriors who completely protect the corresponding segment at the time.
There is no output for input lines that start with the character ‘+’.

Sample Input
9
+ 5 10
+ 7 20
+ 3 15
? 9 12
+ 10 20
? 8 9
+ 6 30
? 8 9
? 9 12

Sample Output
2
3
4
3

一句话题意

有两种操作(共n个,n<=500000), 一个是插入一个[l,r]的区间,另一个是询问一个区间[l,r],前面有多少个区间完全包含了这个区间。

思路

法一:很容易想到的一个搞法是线段树套平衡树,也就是对于插入的区间,把[1,l]都插入一个r,然后对询问的区间就是看[1,l]里面有多少个数>=r,然而这样的空间复杂度是nlog2n,n=50w显然T飞

法二:换种思路,去掉时间限制,把问题看成一个序列,则前面的修改会对后面的询问造成影响。于是我们便想到了CDQ分治中第二点:对于所有在[l,m]内的修改操作,枚举处理它对于[m,r]内的所有操作影响。”所以我们可以对一个操作序列[a,b], 设m=(a+b)/2,先递归处理[a,m], [m+1,b],然后考虑[a,m]里面的插入区间的操作对[m+1,b]里面询问的影响。也就是转化成静态的问题。可以先把区间按照右端点从大到小排序*,然后扫一边,扫到一个插入区间用树状数组就在l处+1,询问就是原有答案加上sum(l)。

上面*号注意,右端点相同时,左端点一定要从小到大排序,举个例子,如果一个询问是 i+1->j,一个插入是i->j,插入一定要排在询问前面才能被统计到

代码

 #include<set>
#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define RG register int
#define rep(i,a,b) for(RG i=a;i<=b;i++)
#define per(i,a,b) for(RG i=a;i>=b;i--)
#define ll long long
#define inf (1<<30)
#define maxn 500005
#define lowbit(x) (x&(-x))
using namespace std;
int n,cnt;
int hash_table[maxn<<],t[maxn<<],ans[maxn];
struct Dat{
char type;
int l,r,id;
}dat[maxn];
inline int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} int pre()
{
char c;
n=read();
rep(i,,n)
{
scanf("%c",&c);dat[i].l=hash_table[++cnt]=read(),dat[i].r=hash_table[++cnt]=read(),dat[i].id=i;
if(c=='+') dat[i].type=;
}
sort(hash_table+,hash_table++cnt);
cnt=unique(hash_table+,hash_table++cnt)-hash_table-;
rep(i,,n)
{
dat[i].l=lower_bound(hash_table+,hash_table++cnt,dat[i].l)-hash_table;
dat[i].r=lower_bound(hash_table+,hash_table++cnt,dat[i].r)-hash_table;
}
} inline bool cmp(const Dat &a,const Dat &b){return a.r==b.r?a.l<b.l:a.r>b.r;} void add(int x,int val)
{
while(x<=cnt)
t[x]+=val,x+=lowbit(x);
} int query(int x)
{
int sum=;
while(x)
sum+=t[x],x-=lowbit(x);
return sum;
} void CDQ(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>;
CDQ(l,mid);
CDQ(mid+,r);
sort(dat+l,dat+r+,cmp);
for(int i=l;i<=r;i++)
{
if(dat[i].type&&dat[i].id<=mid) add(dat[i].l,);
if(!dat[i].type&&dat[i].id>mid) ans[dat[i].id]+=query(dat[i].l);
}
for(int i=l;i<=r;i++)
if(dat[i].type&&dat[i].id<=mid) add(dat[i].l,-);
} inline bool cnm(const Dat &a,const Dat &b){return a.id<b.id;} int main()
{
pre();
CDQ(,n);
sort(dat+,dat++n,cnm);
rep(i,,n) if(!dat[i].type) printf("%d\n",ans[i]);
return ;
}

CDQ分治入门 + 例题 Arnooks's Defensive Line [Uva live 5871]的更多相关文章

  1. COGS 577 蝗灾 [CDQ分治入门题]

    题目链接 昨天mhr神犇,讲分治时的CDQ分治的入门题. 题意: 你又一个w*w正方形的田地. 初始时没有蝗虫. 给你两个操作: 1. 1 x y z: (x,y)这个位置多了z只蝗虫. 2. 2 x ...

  2. cdq分治入门学习 cogs 1752 Mokia nwerc 2015-2016 G 二维偏序

    /* CDQ分治的对象是时间. 即对于一个时间段[L, R],我们取mid = (L + R) / 2. 分治的每层只考虑mid之前的修改对mid之后的查询的贡献,然后递归到[L,mid],(mid, ...

  3. CDQ分治入门

    前言 \(CDQ\)分治是一个神奇的算法. 它有着广泛的用途,甚至在某些题目中还能取代\(KD-Tree\).树套树等恶心的数据结构成为正解,而且常数还小得多. 不过它也有一定的缺点,如必须离线操作, ...

  4. CDQ分治笔记+例题

    CDQ分治是一种离线分治算法,它基于时间顺序对操作序列进行分治. 看这样一个问题: 在一个三维坐标系中,有若干个点,每个点都有对应的坐标 \((X_i , Y_i , Z_i)\) ,我们要对于每个点 ...

  5. cdq分治入门and持续学习orz

    感觉cdq分治是一个很有趣的算法 能将很多需要套数据结构的题通过离线来做 目前的一些微小的理解 在一般情况下 就像求三维偏序xyz 就可以先对x排序 然后分治 1 cdq_x(L,M) ; 2 提取出 ...

  6. caioj1097: [视频]树状数组1(快速求和计算) cdq分治入门

    这题虽然是个树状数组,但是也可以用cdq分治做啊~~,这个就是一个浅显的二维偏序的应用? cdq分治和普通的分治有什么区别? 举个栗子:有4个小朋友,你请他们吃饭,假如你分治搞,就会分成很多子问题—— ...

  7. bzoj3262陌上花开 cdq分治入门题

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  8. 【学术篇】bzoj3262 陌上花开. cdq分治入门

    花儿们已经很累了-- 无论是花形.颜色.还是气味, 都不是为了给人们摆出来欣赏的, 更不是为了当做出题的素材的, 她们并不想自己这些属性被没有生命的数字量化, 并不想和其它的花攀比, 并无意分出个三六 ...

  9. cdq分治入门--BZOJ1492: [NOI2007]货币兑换Cash

    n<=100000天,一开始有s块钱,每天股票A价格ai,B价格bi,每天可以做的事情:卖出股票:按A:B=RTi的比例买入股票.问最后的最大收益.股票可以为浮点数,答案保留三位. 用脚指头想想 ...

随机推荐

  1. C. cltt的幸运数LCAtarjan

    /*C: cltt的幸运数 Time Limit: 1 s      Memory Limit: 128 MB Submit Problem Description 一棵树有n个节点,共m次查询,查询 ...

  2. C/C++内存管理器

    C标准库提供了malloc,free,calloc,realloc,C++标准库还提供了new, new[], delete, delete[].这些用来管理内存,看起来够用了,为啥还要自己写一个内存 ...

  3. openCV 备忘

    yum install python-devel numpy cmake gcc gcc-c++yum install gtk2-devel libdc1394-devel libv4l-devel ...

  4. Spring MVC基础知识整理➣View与Controller数据交互

    概述 Spring MVC是由View—Controller—Model组成,其中View和Controller的数据交互,成为了关注的核心点.MVC中,我们将View中的数据传递到Controlle ...

  5. 封装curl的get和post请求

    /** * GET 请求 * @param string $url */ function http_get($url){ $oCurl = curl_init(); if(stripos($url, ...

  6. jQuery和Zepto冲突问题【解决】

    特殊操作下,项目中同时引入这两个文件时,往往会有些冲突,应该加一句代码避免冲突 <script src="~/js/jquery-2.1.4.js"></scri ...

  7. Codeforces 219E Parking Lot 线段树

    Parking Lot 线段树区间合并一下, 求当前要占的位置, 不包括两端点的写起来方便一点. #include<bits/stdc++.h> #define LL long long ...

  8. Vue 组件(上)转载

    一.定义 组件:应用界面上一个个的区块. 自定义的HTML元素. 二.创建和注册 Vue.extend() 扩展,创建组件构造器 Vue.component()注册组件,2个参数,1为标签,2是组件构 ...

  9. 关于ACtion类利用file类型取得上传文件的内容,名字和内容类型

    上面的Action提供了两个属性:uploadFileName和uploadContentType,这个两个属性分别用于封转上传文件的文件名.上传文件的文件类型.Action类直接通过File类型属性 ...

  10. html-伪类

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...