cyk的分治讲义
分治讲义
请在开始前先确保您已经会了如下知识
1、数组
2、递归函数
3、线段树,树状数组
4、小学的代数知识
由于cykcykcyk实在是tcltcltcl,所以难免讲义可能存在问题
如果有请指出来大力批判我,thanksthanksthanks~
一、一般分治
参考论文:201320132013年国家集训队xhrxhrxhr,201420142014年国家集训队xyz,2016年国家集训队lzzlzzlzz
主定理(Master Theorem):
T(n)=2T(n/2)+O(kn)−>T(n)=O(knlogn)T(n)=2T(n/2)+O(kn)->T(n)=O(knlogn)T(n)=2T(n/2)+O(kn)−>T(n)=O(knlogn)
证明?
考虑递归的每层规模实际上都是O(nk)O(nk)O(nk)的
而每次nnn规模减少一半,总共lognlognlogn层
1、序列分治
一般询问满足某种条件的点对数量
考虑2个点之间的路径
则我们可以在中间一个点统计答案
void solve(int l,int r){
int mid=((l+r)>>1);
solve(l,mid),solve(mid+1,r)
count(l,r);
if(l==r)return;
}
先来看一道简单题
bzoj4979bzoj4979bzoj4979凌晨三点的宿舍
给定一个序列,每个位置一个值hih_ihi
定义222个位置(i,j),i<j(i,j),i<j(i,j),i<j的距离为j−i+hi+hj−2∗min(h[k],k∈[i,j])j-i+h_i+h_j-2*min(h[k],k\in[i,j])j−i+hi+hj−2∗min(h[k],k∈[i,j])
求有多少对节点的距离小于等于ppp
n≤2e5n \le2e5n≤2e5
记得校内考过一道类似的题
考虑分治
对于当前区间l,mid,rl,mid,rl,mid,r
令mnimn_imni表示iii到midmidmid的最小值
求有多少i∈[l,mid],j∈[mid+1,r]i\in[l,mid],j\in[mid+1,r]i∈[l,mid],j∈[mid+1,r]满足
j−i+hi+hj−2∗min(mni,mnj)≤kj-i+h_i+h_j-2*min(mn_i,mn_j)\le kj−i+hi+hj−2∗min(mni,mnj)≤k
假设此时min=mnimin=mn_imin=mni,另一种会在相反的i,ji,ji,j统计到
则hi−i−2∗mni≤k−j−hjh_i-i-2*mn_i\le k-j-h_jhi−i−2∗mni≤k−j−hj
对每个iii插入树状数组后对jjj查询就是了
复杂度O(nlog2n)O(nlog^2n)O(nlog2n)
2、整体二分
整体二分可以相当于普通二分的进化版
考虑普通二分一般是处理多个修改,单个查询
复杂度O(f(a)∗logc)O(f(a)*logc)O(f(a)∗logc),ccc是值域,fff是单次操作复杂度
那如果有多个询问变成O(Q∗f(a)∗logc)O(Q*f(a)*logc)O(Q∗f(a)∗logc)就炸了
而整体二分可以做到O((Q+f(a))∗logc)O((Q+f(a))*logc)O((Q+f(a))∗logc)的复杂度
可以在一定情况下替代一些复杂数据结构
比如树套树之类的
而且时间常数还十分优秀(雾)
比如询问区间第kkk大(不考虑主席树)
如果只有一次询问
我们显然可以二分答案,判断区间是否有k个大于midmidmid的数
虽然一次十分不优
如果有多次询问呢?
发现二分过程中有许多次信息是重复的
怎么连带统计完对所有询问的影响
这时就可以上整体二分了
算法流程
void(二分下界l,二分上界r,队首,队尾){
if(队列空)return;
if(l==r)队列内的所有询问答案为l,return ;
int mid = 上下界中值;
扫描队列,处理询问与修改值小于mid的修改操作(树状数组)。则询问结果存的是(l, m)内数的个数;
还原树状数组。
扫描队列:
若是修改操作,根据修改答案的大小丢进q1与q2;
若是询问操作,if 询问答案+当前贡献 >= 所需答案k 丢入q1;
else 更新询问答案,丢入q2;
solve(l,mid,q1);
solve(mid+1,r,q2);
}
例题:WOJ2802WOJ2802WOJ2802
支持修改,查询区间第kkk大
树套树?
考虑整体二分
把初始数作为修改
假设当前处理qlqlql~qrqrqr之间的操作,数值在lll ~rrr
二分一个数值midmidmid
每遍历一个操作
如果是修改且修改的值小于midmidmid,则加入树状数组,加入q1q1q1
否则加入q2q2q2
如果是询问,则查询区间内满足查询区间的数numnumnum
如果num>knum>knum>k,则加入q1q1q1
否则k−numk-numk−num加入q2q2q2
核心代码
void solve(int l,int r,int st,int des){
if(l>r||st>des)return;
if(l==r){
for(int i=st;i<=des;i++)if(q[i].op)ans[q[i].pos]=l;
return;
}
int mid=(l+r)>>1,cnt1=0,cnt2=0;
for(int i=st;i<=des;i++){
if(q[i].op){
int tmp=query(q[i].r)-query(q[i].l-1);
if(tmp>=q[i].k)q1[++cnt1]=q[i];
else q[i].k-=tmp,q2[++cnt2]=q[i];
}
else{
if(q[i].l<=mid){
q1[++cnt1]=q[i],add(q[i].pos,q[i].val);
}
else q2[++cnt2]=q[i];
}
}
for(int i=1;i<=cnt1;i++) if(!q1[i].op) add(q1[i].pos, -q1[i].val);
for(int i=1;i<=cnt1;i++) q[st+i-1]=q1[i];
for(int i=1;i<=cnt2;i++) q[st+cnt1+i-1]=q2[i];
solve(l, mid, st, st+cnt1-1); solve(mid+1, r, st+cnt1, des);
}
再来一道
WOJ1776WOJ1776WOJ1776
支持区间每个数之间插入一个数,询问区间第kkk大
和上一道差不多吧,单点修改变成区间修改就可以了
用线段树维护
3、CDQ分治
前置
关于二/三维数点
二维数点是一个常见的模型
一般解决方法有:
主席树:带修///在线nlog2nnlog^2nnlog2n,否则nlognnlognnlogn(要离散化)
二维树状数组(值域很小)///线段树(动态开点,常数超大):nlog2nnlog^2nnlog2n(在线)
cdqcdqcdq分治:nlog2nnlog^2nnlog2n(离线)
kd−tree:kd-tree:kd−tree:我不会
而如果上升到三维时,一般就用kd−treekd-treekd−tree或者cdqcdqcdq了
引入
逆序对−>->−>Lis−>->−>归并///Bit−>->−>cdq做−>->−>cdq
进入正题
cdqcdqcdq分治最早是在陈丹琦的集训队作业中,大致思想是将操作区间分成2半,统计左边对右边的贡献,并继续递归求解
大致代码如下:
void cdq(int l,int r){
if(l==r)return;
cdq(l,mid),cdq(mid+1,r);
calc(effect:l~mid->mid+1~r);
}
一般在计算贡献的时候会用数据结构来维护
并在这次统计完后消除影响(不是直接memset)
举个栗子:
对序列单点加,区间求和(woj1684woj1684woj1684)
我们可以用cdqcdqcdq来做
将区间加变成两个前缀加
考虑先将左右区间分别排序
那我们就只需要用一个双指针统计前半段修改对后半段询问的贡献
左右区间分别排序可以在分治左右区间的时候归并实现
void cdq(int l,int r){
if(l==r)return;
cdq(l,mid),cdq(mid+1,r);
int cnt1=l,cnt2=mid+1;
ll res=0;
for(int i=l;i<=r;i++){
if((cnt1<=mid&&q1[cnt1].l<q1[cnt2].l)||cnt2>r){
if(q1[cnt1].op==1)res+=q1[cnt1].val;
q2[i]=q1[cnt1++];
}
else{
if(q1[cnt2].op==3)ans[q1[cnt2].pos]+=res;
if(q1[cnt2].op==2)ans[q1[cnt2].pos]-=res;
q2[i]=q1[cnt2++];
}
}
for(int i=l;i<=r;i++)q1[i]=q2[i];
}
复杂度O(nlogn)O(nlogn)O(nlogn)虽然并没有什么区别,速度慢一点,空间还要大几倍
大家应该都会了吧
来一道简单的例题:
boi2007−Mokiaboi2007-Mokiaboi2007−Mokia:
给定一个2e6∗2e62e6*2e62e6∗2e6大小的棋盘
支持单点加,矩形求和
复杂度要求O(nlog2n)以内O(nlog^2n)以内O(nlog2n)以内
怎么做?
离散化后二维线段树?
TLE+MLETLE+MLETLE+MLE
二维mapmapmap维护BITBITBIT?
常数过大,莫名ReReRe(亲身体验)二进制分组套主席树
考虑cdqcdqcdq分治
定义操作solve(l,r)solve(l,r)solve(l,r)处理(l,mid)(l,mid)(l,mid)之间的修改对(mid+1,r)(mid+1,r)(mid+1,r)的询问的影响
考虑将(l,mid),(mid+1,r)分别(l,mid),(mid+1,r)分别(l,mid),(mid+1,r)分别按照xxx排序
显然我们可以用双指针来保证xxx的有序
那我们相当于只用对于一个查询查找y<askyy<ask_yy<asky的个数
一个BitBitBit就搞定了
inline void cdq(int l,int r){
if(l==r)return;
cdq(l,mid),cdq(mid+1,r);
sort(a+l,a+mid+1,compl),sort(a+mid+1,a+r+1,compl);
int i=l;
for(int j=mid+1;j<=r;j++){
for(;i<=mid&&a[i].l<=a[j].l;i++)
if(a[i].op==1)update(a[i].r,a[i].val);
if(a[j].op==2)ans[a[j].pos]+=query(a[j].r);
}
for(int j=l;j<i;j++)if(a[j].op==1)update(a[j].r,-a[j].pos);
}
再来一道:陌上菊开
题意:
有nnn个人,每个人有3个属性a,b,ca,b,ca,b,c
定义一个人iii比jjj强当且仅当ai>aj,bi>bj,ci>cja_i>a_j,b_i>b_j,c_i>c_jai>aj,bi>bj,ci>cj
对每个人求他比多少个人强
关于归并排序优化一个log/log/log/减少常数
cdqcdqcdq维护动态凸包
cdqcdqcdq优化dpdpdp
我们发现cdqcdqcdq其实就是通过分割区间计算左边对右边的贡献
本质就是按照时间将动态的操作变成静态的
那对于一些递推的dpdpdp(一般是斜率dpdpdp),也可以来优化转移
NOI2007−CashNOI2007-CashNOI2007−Cash
有AB两种货币,第iii天可以花一定的钱,买到AAA券和BBB券,且A:B=RateiA:B=Rate_iA:B=Ratei,也可以卖掉OPOPOP%的AAA券和BBB券,每天ABABAB价值为AiA_iAi和BiB_iBi。
开始有S元,n天后手中不能有AB券,问最大获益。n≤1e5n\le 1e5n≤1e5
考虑令f[i]f[i]f[i]为第iii天得到的最多的AAA券,g[i]g[i]g[i]为第iii天得到的最多的BBB券
则g[i]=f[i]/rate[i]g[i]=f[i]/rate[i]g[i]=f[i]/rate[i]
那显然有个n2n^2n2的dpdpdp,暴力枚举前面每一天转移
怎么优化
考虑如果前面i,ji,ji,j两天对于决策nownownow的影响,如果iii比jjj优的话
则(f[i]−f[j])∗a[now]−(g[i]−g[j])∗b[now]>0(f[i]-f[j])*a[now]-(g[i]-g[j])*b[now]>0(f[i]−f[j])∗a[now]−(g[i]−g[j])∗b[now]>0
即g[i]−g[j]f[i]−f[j]<−a[now]b[now]\frac{g[i]-g[j]}{f[i]-f[j]}<-\frac{a[now]}{b[now]}f[i]−f[j]g[i]−g[j]<−b[now]a[now]
注意特判一个f[i]=f[j]f[i]=f[j]f[i]=f[j]的情况
如果将(f[i],g[i])(f[i],g[i])(f[i],g[i])作为平面上的点,那也就是我们维护一个上凸壳
则对于每一个nownownow,我们找到最后一个满足相邻2点斜率小于−a[now]b[now]-\frac{a[now]}{b[now]}−b[now]a[now]的点,并把这个点更新当前节点的答案
但我们发现这个凸包在不断变化
考虑splay动态维护 cdqcdqcdq分治维护凸包
具体的我们可以使nownownow保持有序
就可以一边扫凸包一边更新了
cdqcdqcdq分治中途把凸包和−a[now]b[now]-\frac{a[now]}{b[now]}−b[now]a[now]顺带归并排序
复杂度O(nlogn)O(nlogn)O(nlogn)
更深入的讨论
前提:忽略KD−TreeKD-TreeKD−Tree(虽然应该也没人会……),后面我会讲的
例1: 有nnn个人,每个人有333种能力a,b,ca,b,ca,b,c
定义一个人iii比另一个jjj有能力当且仅当aj<ai,bj<bi,cj<cia_j<a_i,b_j<b_i,c_j<c_iaj<ai,bj<bi,cj<ci
对每个人求出他比多少人有能力(n≤1e5)(n\le 1e5)(n≤1e5)
树套树?二维BitBitBit?
cdqcdqcdq分治
首先按照aaa排序,把(bi,ci)(b_i,c_i)(bi,ci)视为二维坐标
就变成了单点加,区间求和
和上一道类似,O(nlog2n)O(nlog^2n)O(nlog2n)
例2: 有nnn个人,每个人有444种能力a,b,c,da,b,c,da,b,c,d
定义一个人iii,比另一个人jjj有能力当且仅当
aj<ai,bj<bi,cj<ci,dj<dia_j<a_i,b_j<b_i,c_j<c_i,d_j<d_iaj<ai,bj<bi,cj<ci,dj<di
对每个人求出他比多少个人有能力
树套树套树?三维mapmapmap维护BitBitBit?
cdqcdqcdq套cdqcdqcdq
可以先对aaa排序
考虑当前cdq(l,r)cdq(l,r)cdq(l,r)
将左边和右边双指针排序后记录一下每个原来是在(l,mid)还是(mid+1,r)(l,mid)还是(mid+1,r)(l,mid)还是(mid+1,r)
那现在已经保证a,ba,ba,b有序了
我们在内层的cdqcdqcdq可以继续套一个双指针
保证当前ccc有序
将在当前序列左边求在原来的(l,mid)(l,mid)(l,mid)一边的以ddd为下标记录
右边在原来的(mid+1,r)(mid+1,r)(mid+1,r)的用树状数组查询就可以了
复杂度O(nlog3n)O(nlog^3n)O(nlog3n)
是不是cdqcdqcdq其实就是用一个logloglog的代价保证了一维的有序
但我们发现一个问题:每多一维我们都要花费一个logloglog的代价来稳定这一维
但是暴力只需要多1的常数
考虑555维偏序
cdq套cdq套cdq:nlog4ncdq套cdq套cdq:nlog^4ncdq套cdq套cdq:nlog4n,暴力5∗n25*n^25∗n2
n=2e4n=2e4n=2e4时2种的效率已经几乎没有区别了(实际运行效率)
考虑有没有别的做法?
当然有
引进一个东西-bitsetbitsetbitset
基本原理是用每32位连续的数字压成一个intintint(似乎是这样吧)
相当于一堆0/10/10/1,
而且可以做类似集合一样取交集,并集(&,∣)(\&,|)(&,∣)之类的
查询0/1的个数之类的
常数是一般运算的132\frac 1{32}321(似乎有人说集合的操作是size/64size/64size/64?)
某些题目就可以用bitsetbitsetbitset做到n2n^2n2过十万(比如woj4302woj4302woj4302)
那考虑这个怎么用bitsetbitsetbitset?
我们可以分别对于每一维求出比当前一个数小的元素集合
那是不是取一个交集就是答案了?
复杂度大约是O(n2/64)O(n^2/64)O(n2/64)?
然而当你写完这个程序兴致勃勃交上去,mlemlemle愉快
bitset不要空间?
怎么办?考虑分块
将每维每n\sqrt nn个分一组,建一个bitsetbitsetbitset
每次暴力跳n\sqrt nn次得到当前答案集合
复杂度O(能过) O(k∗qn)?O(k*q\sqrt n)?O(k∗qn)?
详见woj3230woj3230woj3230
当然如果你觉得bitsetbitsetbitset慢也可以手写
参见某位dalao的blog
4、二进制分组
一般在2种情况下会用到:
1、要求强制在线(否则cdqcdqcdq呗)
2、支持将信息合并(也就是说如果要(a,b)(a,b)(a,b)的答案,可以通过(a,k],(k,b)(a,k],(k,b)(a,k],(k,b)信息合并在(log)(log)(log)以内左右的时间得到)
二进制分组也是一个奇♂妙的东西
考虑到某些数据结构在解决某些问题的时候是不能修改的
比如主席树解决区间第kkk大,如果带一个修改就完全不可做了
又或者主席树可以解决二维数点(实际上二维数点和区间第k大是类似的模型),
但是带加点/修改操作就不可做了
而二进制分组则可以以一个logloglog的代价将动态操作变成静态的
考虑将当前操作数拆成二的幂次从大到小的和的形式
比如:
21=16+4+1{ }21=16+4+121=16+4+1
22=16+4+222=16+4+222=16+4+2
23=16+4+2+123=16+4+2+123=16+4+2+1
24=16+824=16+824=16+8
这有什么用的?
不如对修改的操作分组按照这样分组
那我们对于每一组分别用数据结构来维护,查询在每一组分别查询就是了
考虑新加入一个修改操作
如果在二进制下可以发现如果已经有“当前位”的数就会向前进一位
那对于新的修改操作处理就很简单了
void insert(now){
build(now),siz[++top]=1;
while(siz[top]==siz[top-1]){
merge(top,top-1),siz[top-1]+=siz[top],top--;
}
}
考虑时空复杂度证明:
对于合并,显然任何一次建出的数据结构都只会被合并O(logn)O(logn)O(logn)次(20,21,22......)(2^0,2^1,2^2......)(20,21,22......)
实际上仔细分析会发现
添加第iii个元素的时候,合并的总元素个数是lowbit(i)lowbit(i)lowbit(i),也就是iii在二进制位下最低一位的权值
那复杂度就是
∑i=1mO(f(lowbit(i)))\sum_{i=1}^{m}O(f(lowbit(i)))i=1∑mO(f(lowbit(i)))
=∑i=1logm⌊n2i+1+0.5⌋∗f(2i)≤∑i=1logmO(f(n))=\sum_{i=1}^{logm}\lfloor {\frac {n}{2^{i+1}}+0.5}\rfloor *f(2^i)\le \sum_{i=1}^{logm}O(f(n))=i=1∑logm⌊2i+1n+0.5⌋∗f(2i)≤i=1∑logmO(f(n))
=O(f(n)logn)=O(f(n)logn)=O(f(n)logn)
考虑询问,显然同时存在的组数是不会超过logloglog的
那总共就只有不到logloglog次询问
因此通过二进制分组,我们以一个logloglog的代价将动态操作变成了静态
例题:
二维数点,支持加点
如果没有加点操作我们显然可以主席树nlognnlognnlogn解决(怎么做),或者cdq/二维bitcdq/二维bitcdq/二维bit做到nlog2nlog^2nlog2也不赖
考虑对加点操作二进制分一下组
那就变成了平面有一堆点,然后单纯的二维数点了
复杂度O(nlog2n)O(nlog^2n)O(nlog2n)
既然可以二进制分组,那有没有三进制分组?四进制分组之类的?
显然可以发现随着进制kkk的增大,我们合并的操作会越来越少
但相应的,一次询问的复杂度会上升
在对于一些特殊的题目(比如什么98%98\%98%都是修改之类的)
也许就可以用到更高的分组(雾)
5、线段树分治
大致思想就是把修改建成一颗线段树
然后考虑询问,考虑如果左区间的修改对该询问有影响
就将这次询问加入队列递归询问左区间
右区间对该询问有影响类似
和二进制分组其实很类似
只是将每次的合并状态都记录着
想象一下线段树的结构
而且一般的二进制分组只能解决全局的询问,面对某些只询问一些修改的时候就难以为力了
比如woj4408woj4408woj4408
而这时候就有一种补救方法
用类似于线段树一样的结构,每次向上pushuppushuppushup存储一下当前状态
每次多一个修改就是填一个节点
(与二进制分组的时空复杂度区别)
那如果加一个撤销某次修改的操作呢?
例题UOJ#191−UnknownUOJ\# 191-UnknownUOJ#191−Unknown
这些更深入的就不讲了,因为我也不会 估计没人想听了
可以参见2016年lzzlzzlzz国家集训队论文
练手题:woj4299woj4299woj4299,woj4408woj4408woj4408
难♂题:UR#14UR\#14UR#14 思考熊(最短4k+4k+4k+)
咕咕咕
咕咕咕
二、树上分治
既然序列可以通过分治处理重复信息做到nlognnlognnlogn
那显然我们也可以通过同样的方法提到树上来做
6、点分治
序列上可以通过midmidmid来保证复杂度每次减半
树上呢?
树的重心:如果一个点满足其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心
因为我们可以发现这样可以保证去掉这个点之后形成的森林的点数最为平均
可以证明:每次去掉重心后树的规模减少12\frac 1 221
这很显然,否则我们重心肯定能走到这颗更大的树内
为什么要点而不是边?
也有边分治,但是特殊情况较多
在菊花图上还要特殊处理
而且最主要的是
我们发现去掉一个点之后会出现多个子树,但是去掉一条边却只会出现2颗子树
那由主定理可得点分治复杂度为O(f(n)logn)O(f(n)logn)O(f(n)logn)
事实上我们可以发现这个logloglog很小
而在一条链上时logloglog达到上界
例题:POJ1741POJ1741POJ1741:求树上距离≤k\le k≤k的点对个数
直接枚举显然是O(n2)O(n^2)O(n2)的
考虑点分治
对于当前分治中心
我们只需要统计经过了当前分治中心的路径个数(没经过的肯定会在其他分治中心被统计)
对于每一个子树dfsdfsdfs出当前子树所有点到中心的距离
假设我们已经得到了前面所有子树到当前中心的深度
考虑新加入一个点,那是不是前面所有和这个点距离和小于等于kkk的点都有贡献
那将每次子树的距离排个序,双指针统计就可以了
复杂度T(n)=S∗T(ns)+O(nlogn)−>T(n)=O(nlog2n)T(n)=S*T(\frac n s)+O(nlogn)->T(n)=O(nlog^2n)T(n)=S∗T(sn)+O(nlogn)−>T(n)=O(nlog2n)
在一些比较特殊的情况中,我们是没办法直接对于子树分别统计的
而需要将所有信息放在一块处理
但比如说统计路径的时候,会出现同一颗子树中2个点拼在一起的不合法的情况
这时候就需要再分别递归子树求出对于单独一颗子树的答案减去
就是这样
void calc(int u,int dep,int f){
ans+=f*query(u,dep);
}
void solve(int u){
calc(u,0,1);
for(v->son[u]){
calc(v,1,-1);
solve(v);
}
}
Codechef:Prime Distance On TreeCodechef:Prime\ Distance\ On\ TreeCodechef:Prime Distance On Tree
求树上所有距离为质数的路径个数
考虑只能处理cnt[i]cnt[i]cnt[i]表示距离为iii的点的个数,枚举统计
复杂度是O(nlogn∗num)=O(n2)O(nlogn*num)=O(n^2)O(nlogn∗num)=O(n2)不如暴力
似乎不好统计了
考虑处理出cnt[i]cnt[i]cnt[i]表示到当前中心距离为iii的点的个数
ans=∑j=prime∑ijcnt[i]∗cnt[j−i]=∑j=primef[j]ans=\sum_{j=prime}\sum_{i}^{j}cnt[i]*cnt[j-i]=\sum_{j=prime}f[j]ans=∑j=prime∑ijcnt[i]∗cnt[j−i]=∑j=primef[j]
发现这是一个卷积的形式,可以fftfftfft优化得到每一个fff,再枚举质数统计答案
复杂度O(nlog2n)O(nlog^2n)O(nlog2n)
IOI2011IOI2011IOI2011—RaceRaceRace
关于操作树上点分(论文)
7、边分治
暂时咕咕
8、动态点分治
码量++,调试难度+++++码量++,调试难度+++++码量++,调试难度+++++
9、链分治
三、根号类算法
201420142014国集lzylzylzy,2013ljq2013ljq2013ljq,2017xmk2017xmk2017xmk,2015zxy2015zxy2015zxy
1、分块
1.一般分块
2.树上分块
3.均值法
4.重构块
2、莫队
1.普通莫队
2.带修莫队
3.树上莫队
3、莫队与分块结合
四、有关的数据结构
1、KD-Tree
练习题:
一、分治
1、整体二分
1、woj2802woj2802woj2802 动态区间第k大
2、woj1776woj1776woj1776 K大数查询
3、woj4034woj4034woj4034 Meteors
4、woj2885woj2885woj2885 接水果
关键词: 扫描线
传送门
5、woj3532woj3532woj3532 混合果汁
关键词: 线段树
传送门
6、woj4402woj4402woj4402 Attack
关键词: 整体二分套cdqcdqcdq
2、CDQCDQCDQ分治
1、woj3964woj3964woj3964 Mokia
2、woj3101woj3101woj3101 陌上花开
3、woj4326woj4326woj4326 数列
4、woj2063woj2063woj2063Cash
5、woj4403woj4403woj4403四维偏序
6、woj3059woj3059woj3059天使玩偶
7、woj3607woj3607woj3607动态逆序对
8、woj3230woj3230woj3230五维偏序
9、woj2018woj2018woj2018城市建设
传送门
cdqcdqcdq分治+最小生成树好题
10、woj4426woj4426woj4426共点圆
11、BZOJ4237稻草人
12、WOJ2257拦截导弹
二、树上分治
1、点分治
1、poj1741
2、BZOJ2152
3、BZOJ1316
4、洛谷P4149
5、Codechef
关键词:点分治+fftfftfft
6、BZOJ1758
关键词:点分治+分数规划