cdq分治与整体二分

cdq来源于2008年国家集训队作业陈丹琦(雅礼巨佬),用一个log的代价完成从静态到动态(很多时候是减少时间那一维的)。

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

整体二分就是将所有询问一起二分,然后获得每个询问的答案。CDQ相比整体二分略有不同,整体二分是按照答案进行分治。

cdq和整体二分适用范围:处理一些用数据结构(如树套树)做起来非常令人难受的题。需要离线。

很多时候需要还原修改操作。

推荐阅读:http://www.docin.com/p-950607443.htmlhttps://wenku.baidu.com/view/52f9c11cff00bed5b9f31d2d.html

update20180315:

CDQ分治

​ 抱歉上次因为能力不足没有讲清楚。

1 普通cdq分治(三维偏序问题)

​ 按照线段树的形态递归的CDQ分治,保证每一对三元组在线段树上都有且仅有一个LCA(这不废话吗),而这一组答案就会且仅会在LCA处计算。在每个LCA处,只计算左边的操作对右边的询问的贡献。

​ 具体做法:一维是用来当做"时间"分治(假设为a),一维是提前排好序的(假设为b),一维放在数据结构里面查询(假设为c)。 对于每一层cdq,我们二分一个时间mid,仍按照b的顺序依次处理,对于a<=mid的修改操作,我们放入数据结构在c位置修改,对于a>mid的查询操作,我们在数据结构里面根据c位置查询。这样我们就把a<=mid的操作对a>mid的操作的贡献全都算完了,然后把 a<=mid 和 a>mid 的操作分到左右两边,递归下去。

2 cdq套cdq(四维偏序问题)

​ 当维数为4的时候,因为多出来的一维,就只能先确定一维的大小关系,使这一维不会影响内层的cdq分治。

​ 具体做法:对于cdq1(外层cdq),我们二分一个mid,然后把b<=mid的修改操作和b>mid的查询操作拿出来,这个时候我们确定拿出来的这些操作,修改的操作的b一定小于查询的操作的b,那么b这一维我们就可以不管了,所以我们把他们按照a大小关系重新排序,然后直接做普通的cdq分治(内层cdq)。

3 cdq+凸包、cdq+半平面交、cdq+背包

​ cdq是一个思想,一个技巧,说白了就是用一维来分治,用一个log时间换取排除这一维的干扰,cdq可以套在乱七八糟的东西上,也没有固定的格式,最重要的是适合题目。

下面是原内容:

Mokia

维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

二维单点修改,矩形查询。
首先修改/查询之间的顺序就是时间,我们按时间来分治。
但是由于是二维的,为了省空间不开二维的数据结构,
我们一开始把所有操作按x轴排序,
每次处理我们只需要扫描一下x轴,把y轴的修改/查询放到一个一维树状数组里就好了。
矩形查询拆为4个前缀和查询
具体步骤如下:
(1)把操作离线下来,然后按x轴排序。(必要时离散化)
(2)分治区间[L, R](L, R为时间,即操作的编号),取mid,从L到R遍历操作,
将mid之前的修改加入一维树状数组,将mid之后的查询在一维树状数组里查询。
(3)注意要还原修改操作,从L到R遍历操作,遇到修改操作,将修改操作改回去。
(4)开一个临时数组,两个指针(一个指针指向左区间的左端点,另一个指针指向右区间的左端点),
从L到R遍历操作,将mid之前的操作放到左区间,将mid之后的操作放到右区间。
最后把临时数组赋值给操作数组。
(5)递归[L, mid],[mid + 1, R],回到(2)。
注意递归边界
在分治的每一层的区间内,x轴都是有序的。虽然时间无序,但是我们遍历操作时按照mid来划分了。
inline void cdq(int l,int r) {
if(l==r) return;
int mid=l+r>>1;
for(int i=l;i<=r;i++)
if(c[i].opt==1&&c[i].id<=mid) add(c[i].y,c[i].c);
else if(c[i].opt==2&&c[i].id>mid) ans[c[i].qid]+=c[i].c*sum(c[i].y);
for(int i=l;i<=r;i++)
if(c[i].opt==1&&c[i].id<=mid) add(c[i].y,-c[i].c);
int h1=l,h2=mid;
for(int i=l;i<=r;i++)
if(c[i].id<=mid) tmp[h1++]=c[i];
else tmp[++h2]=c[i];
for(int i=l;i<=r;i++) c[i]=tmp[i];
cdq(l,mid); cdq(mid+1,r);
}

  

动态逆序对

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。

给1到n的一个排列,按照某种顺序依次删除m个元素.

你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

$n \leq 1e5 , m \leq 5e4$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
const int maxn=1e5+10,maxm=5e4+10;
ll n,m,a[maxn],id[maxn],tot; ll aa;char cc;
ll read() {
aa=0;cc=getchar();
while(cc<'0'||cc>'9') cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
return aa;
} struct Ask{
int id,x,y;
}ask[maxn]; ll ans[maxn],now[maxn];
bool cmp(const Ask& a,const Ask& b) {
return now[a.id]<now[b.id];
}
bool cmp2(const Ask& a,const Ask& b) {
return a.id<b.id;
} int sz[maxn];
void add(int pos,int x){
while(pos<=n) {
sz[pos]+=x;
pos+=pos&-pos;
}
} int q(int pos) {
ll rs=0;
while(pos) {
rs+=sz[pos];
pos-=pos&-pos;
}
return rs;
} void cdq(int l,int r) {
if(l==r) return;
int mid=(l+r)>>1,pos1=l,pos2=mid+1;
for(int i=l;i<=r;++i) {
if(ask[i].x<=mid) add(ask[i].y,1),now[ask[i].id]=pos1++;
else ans[ask[i].id]+=q(n)-q(ask[i].y),now[ask[i].id]=pos2++;
}
sort(ask+l,ask+r+1,cmp);
for(int i=l;i<=mid;++i) add(ask[i].y,-1);
cdq(l,mid);cdq(mid+1,r);
} int main() {
n=read();m=read();
for(int i=1;i<=n;++i) {
a[i]=read();
id[a[i]]=i;
}
int x;
for(int i=1;i<=m;++i) {
x=read();
ask[++tot].x=id[x];
ask[tot].y=x;
a[id[x]]=0;
}
for(int i=1;i<=n;++i) if(a[i]) {
ask[++tot].x=i;
ask[tot].y=a[i];
}
for(int i=1;i<=n/2;++i) swap(ask[i],ask[n-i+1]);
for(int i=1;i<=n;++i) ask[i].id=i;
cdq(1,n);
for(int i=1;i<=n;++i) ask[i].x=n+1-ask[i].x,ask[i].y=n+1-ask[i].y;
sort(ask+1,ask+n+1,cmp2);
cdq(1,n);
for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
for(int i=n;i>n-m;--i) printf("%lld\n",ans[i]);
return 0;
}

Partial Order (3D)

有N个人,每个人有三种能力值Pi,Qi,Ri。如果Pi>Pj && Qi>Qj && Ri>Rj,称I比J有能力.现在要求出最长的一个序列A=(A1,A2,…,At),满足Ai比Ai+1有能力。

$N \leq 4e4$

尝试在这个问题上进行分治。
定义过程Solve(l,r),能够得到F[l]..F[r]的值
Solve(l,r):
Solve(l,mid)
处理[l,mid]中元素对[mid+1,r]中F[x]取值的影响
Solve(mid+1,r)

Simplified Partial Order(4D)

有N个人,每个人有四种能力值Pi,Qi,Ri,Si。
如果Pi>Pj && Qi>Qj && Ri>Rj && Si>Sj,称I比J有能力。
对每一个人,输出任意一个比他有能力的人编号,或声明没有人比他有能力。

Partial Order(4D)

有N个人,每个人有三种能力值Pi,Qi,Ri,Si。

如果Pi>Pj && Qi>Qj && Ri>Rj && Si>Sj,称I比J有能力。

现在要求出最长的一个序列A=(A1,A2,…,At),满足Ai比Ai+1有能力。

$N \leq 2e4$

分治套分治(cdq套cdq)
首先我们按照p一维排序。
Solve(l,r):
Solve(l,mid)
do sth
Solve(mid+1,r)
do sth需要考虑的问题:
给定带权点集X=(Qi,Ri,Si) [l<=i<=mid],权值F[i]
给定(r-mid)个询问(Qj,Rj,Sj) [mid+1<=j<=r]
对于每个询问,回答点集中满足Qi<Qj,Ri<Rj,Si<Sj的最大权值。
类似于3D偏序问题。
Solve2(l,r):
Solve2(l,mid)
处理(l,mid)中点对(mid+1,r)中询问的影响
Solve2(mid+1,r)
所以说总体就是这样的:
Solve(l,r)
Solve(l,mid)
创建一个[l,r]的副本并按照Q[i]分治
Solve2(l,r)
Solve(mid+1,r)

  

天使玩偶

维护二维点集P,支持以下两个操作

(1)插入点(x,y)

(2)给定询问(x,y),求点集中离询问点最近的点

距离定义为曼哈顿距离Dis(P1,P2)=|x1-x2|+|y1-y2|

$N \leq 3e5$

Star(hdu5126)

在一个三维空间当中,每次进行一个操作,添加一个点或者统计空间中的某一个长方体范围内的所有点

$N \leq 5e4$

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=4e5+10;
int T,n,tot,qtot,ans[maxn/6];
int pz[maxn/4],tz; int aa;char cc;
int read() {
aa=0;cc=getchar();
while(cc<'0'||cc>'9') cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
return aa;
} int ef(int x) {
int l=1,r=tz,mid;
while(l<=r) {
mid=(l+r)>>1;
if(pz[mid]==x) return mid;
if(pz[mid]<x) l=mid+1;
else r=mid-1;
}
}
int xx[maxn],yy[maxn],zz[maxn],fnum[maxn];
struct Ask{
int qid,id;
}ask[maxn],ask1[maxn],ask2[maxn];
bool cmp(const Ask& a,const Ask& b) {
return xx[a.id]==xx[b.id]? a.id < b.id : xx[a.id] < xx[b.id];
}
bool cmp2(const Ask& a,const Ask& b) {
return yy[a.id]==yy[b.id]? a.id < b.id : yy[a.id] < yy[b.id];
} void add(int x,int y,int z,int num) {
fnum[++tot]=num;ask[tot].id=tot;
xx[tot]=x;yy[tot]=y;zz[tot]=z;
if(num) ask[tot].qid=qtot;
} int sz[maxn];
int q(int pos) {
int rs=0;
while(pos) {
rs+=sz[pos];
pos-=pos&-pos;
}
return rs;
} void chge(int pos,int x) {
while(pos<=tz) {
sz[pos]+=x;
pos+=pos&-pos;
}
} void cdq2(int l,int r) {
if(l>=r) return;
int mid=(l+r)>>1,now=0;
cdq2(l,mid); cdq2(mid+1,r);
for(int i=l;i<=mid;++i) if(!fnum[ask1[i].id]) ask2[++now]=ask1[i];
for(int i=mid+1;i<=r;++i) if(fnum[ask1[i].id]) ask2[++now]=ask1[i];
sort(ask2+1,ask2+now+1,cmp2);
for(int i=1;i<=now;++i) {
if(!fnum[ask2[i].id]) chge(zz[ask2[i].id],1);
else ans[ask2[i].qid]+=fnum[ask2[i].id]*q(zz[ask2[i].id]);
}
for(int i=1;i<=now;++i) if(!fnum[ask2[i].id]) chge(zz[ask2[i].id],-1);
} void cdq(int l,int r) {
if(l>=r) return;
int mid=(l+r)>>1,now=0;
cdq(l,mid); cdq(mid+1,r);
for(register int i=l;i<=mid;++i) if(!fnum[ask[i].id]) ask1[++now]=ask[i];
for(register int i=mid+1;i<=r;++i) if(fnum[ask[i].id]) ask1[++now]=ask[i];
sort(ask1+1,ask1+now+1,cmp);
cdq2(1,now);
} void clear() {
memset(ans,0,sizeof(ans));
tz=tot=qtot=0;
} int main() {
T=read();
int op,x,y,z,x1,y1,z1;
while(T--) {
n=read(); clear();
for(int i=1;i<=n;++i) {
op=read(); x=read(); y=read(); z=read();
if(op==1) add(x,y,z,0),pz[++tz]=z;
else {
x1=read();y1=read();z1=read();++qtot; pz[++tz]=z1; pz[++tz]=z-1;
add(x-1,y-1,z-1,-1); add(x1,y1,z1,1);
add(x1,y-1,z-1,1); add(x-1,y1,z-1,1); add(x-1,y-1,z1,1);
add(x-1,y1,z1,-1); add(x1,y-1,z1,-1); add(x1,y1,z-1,-1);
}
}
sort(pz+1,pz+tz+1);
tz=unique(pz+1,pz+tz+1)-(pz+1);
for(int i=1;i<=tot;++i) zz[i]=ef(zz[i]);
cdq(1,tot);
for(int i=1;i<=qtot;++i) printf("%d\n",ans[i]);
}
return 0;
}

  

cash(noi2007)

小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称 A 券)和 B 纪念券(以下简称 B 券).

每个持有金券的顾客都有 一个自己的帐户.金券的数目可以是一个实数.

每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券 当天可以兑换的人民币数目.我们记录第 K 天中 A 券和 B 券的价值分别为 AK 和 BK(元/单位金券).

为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法. 比例交易法分为两个方面:

A) 卖出金券:顾客提供一个[0,100]内的实数 OP 作为卖出比例,其意 义为:将 OP%的 A 券和 OP%的 B 券以当时的价值兑换为人民币;

B) 买入金券:顾客支付 IP 元人民币,交易所将会兑换给用户总价值为

IP 的金券,并且,满足提供给顾客的 A 券和 B 券的比例在第 K 天恰好为 RateK;

例如,假定接下来 3 天内的 Ak、Bk、RateK 的变化分别为:

时间

Ak

Bk

RAtek

第一天

1

1

1

第二天

1

2

2

第三天

2

2

3

假定在第一天时,用户手中有 100 元人民币但是没有任何金券. 用户可以执行以下的操作:

时间

用户操作

人民币(元)

A 券的数量

B 券的数量

开户

100

0

0

第一天

买入 100 元

0

50

50

第二天

卖出 50%

75

25

25

第二天

买入 60 元

15

55

40

第三天

卖出 100%

205

0

0

注意到,同一天内可以进行多次操作.

小 Y 是一个很有经济头脑的员工,通过较长时间的运作和行情测算,

他已经 知道了未来 N 天内的 A 券和 B 券的价值以及 Rate

他还希望能够计算出来,如 果开始时拥有 S 元钱,那么 N 天后最多能够获得多少元钱.

$N \leq 1e5$

我们可以贪心地知道每次卖出金券都是把手中的所有都卖出去最优。
假如用f[i]表示第i天手中的A券,我们可以得到一个dp方程:
ans=max(ans,f[j]*a[i]+f[j]/rate[j]*b[i])
f[i]=ans*rate[i]/(a[i]*rate[i]+b[i])
对于一个i我们需要枚举<i的j(上一次买入金券的时间)。
所以说复杂度是n平方的。
对于刚才的式子,我们假设j比k优并且f[j]<f[k]
令g[i]=f[i]/rate[i],那么有
f[j]*a[i]+g[j]*b[i]>f[k]*a[i]+g[k]*b[i]
(f[j]-f[k])*a[i]+(g[j]-g[k])*b[i]>0
=>
(g[j]-g[k])/(f[j]-f[k])<-a[i]/b[i]
我们发现式子左边相当于点(f[j],g[j])与(f[k],g[k])的斜率
如果我们维护一个当f增大g减小的上凸壳,
那么我们就需要找到第一个斜率<-a[i]/b[i]的线段(二分)。
由于随着i变大,f、g并不单调,所以不能直接用栈维护凸壳
可以用平衡树来维护(比如splay什么的)
我们考虑用cdq分治来做这个问题。
我们先按照时间排序(就相当于不排序嘛)
solve(l,r):
solve(l,mid)(然后左区间就按照f排好序了)
设置一个右区间的副本并把他按照-a[i]/b[i]排序。
扫一遍更新右区间的f
solve(mid+1,r)(然后右区间就按照f排好序了)
把左右区间合并起来使他们按照f排好序(就相当于归并排序嘛)

  

MachineWorks

你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益。

可以租借的机器有M台。每台机器有四个参数D,P,R,G。

你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器。

从第D+1天起,操作机器将为你产生每天G的收益。在你不再需要机器时,可以将机器卖掉,一次性获得R的收益。

厂房里只能停留一台机器。不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台。

在第N+1天,你必须卖掉手上的机器。

求第N+1天后能获得的最大资金。

$N \leq 1e5$

我们将机器按照D排序。
首先考虑dp。设f[i]表示第i天卖掉机器(让厂房空出来)的最大资金。
f[i]=max(f[i-1],f[j]-P[j]+R[j]+(D[i]-D[j]-1)*G[j])
而f[j]-P[j]+R[j]+(D[i]-D[j]-1)*G[j]
=f[j]-P[j]+R[j]-(D[j]+1)*G[j]+D[i]*G[j]
令A[j]=f[j]-P[j]+R[j]-(D[j]+1)*G[j](只和j有关)
那么:f[i]=max(f[i-1],A[j]+D[i]*G[j])
很像斜率优化的式子,而且D单调。
我们就需要维护一个上凸壳。
但是A和G不单调,所以说还是需要cdq分治。

  

K大数查询

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c(即一个位置可以没有数也可以有多个数)

如果是2 a b c形式,表示询问从第a个位置到第b个位置,第c大的数是多少。

操作1中$c \leq N$,操作2中$c \leq Maxlongint$

$N,M \leq 5e4$

因为操作1中c<=N,答案种数比较少,所以我们考虑对答案分治。
就是相当于把所有询问分到N个答案上去。
假如说当前区间是[l,r],那么目前分到这个区间的所有询问的答案一定在[l,r]中。
我们再把这些询问分成两组,一组答案是在[l,mid]中,一组答案是在[mid+1,r]中。
这样就可以继续分治下去最后得到所有答案所对应的询问。
那么现在问题转化为了判断一个询问被分到哪一组。
也就是说判断这个询问的区间内有多少数的数值是在区间[l,mid]中的。
我们就可以用树状数组维护这个东西,按照操作顺序搞一搞。
涉及树状数组区间修改区间查询。

Meteors

有n个国家和m个空间站,每个空间站都属于一个国家,一个国家可以有多个空间站。

所有空间站按照顺序形成一个环,也就是说,m号空间站和1号空间站相邻。

现在,将会有k场流星雨降临,每一场流星雨都会给区间[li,ri]内的每个空间站带来ai单位的陨石。

每个国家都有一个收集陨石的目标pi,即第i个国家需要收集pi单位的陨石。

询问:每个国家最早完成陨石收集目标是在第几场流星雨过后。

1<=n,m,k<=300000

对于当前区间[l,r],保证目前在这里的所有国家(询问)答案都在[l,r]之间。
用一个数组cur表示这些询问在前l-1场流星雨中的获得量
用线段树或树状数组计算[l,mid]的流星雨,
然后对于每个国家加上对应部分的流星雨。
如果加上后已经达到需要的值,就把这个国家划分到左区间,否则右区间
注意要还原修改操作,还有处理无解情况:可以增加一个INF的流星雨。

  

Package

有N个物品,每个物品的重量是Wi,价值是Gi
每个物品只能取一个
给定Q个询问,每个询问由两个数(X,I)组成
给定最大容量为X的背包,使用除了第i件物品以外的所有物品,能够得到的最大价值之和

$N \leq 100 , X \leq 10000 , Q \leq 1000000$

考虑01背包复杂度NX,因为每加入一个单个物品的复杂度是X。
询问非常多,但是物品很少,我们考虑把不能选物品相同的询问一起考虑。
扩展成维护不能选物品在区间[l,r]中的询问一起考虑。
假如S是不选区间[l,r]做的01背包情况
然后每次将区间划分成[l,mid]、[mid+1,r]就是在S的基础上继续做01背包。
[l,mid]就是在S基础上加入mid+1~r的物品,
而[mid+1,r]就是在S基础上加入l~mid的物品。
于是询问(X,I)的答案就是当区间为[I,I]的S里面容量为X的值。

  

Attack

chnlich非常喜欢玩三国志这款游戏,并喜欢用一些策略出奇制胜。现在,他要开始征服世界的旅途了。
他的敌人有N座城市和N个太守,N个城市可以看作在二维平面上的N个点。
N座城市的标号为0,1,2,……,N-1。
第i座城市的坐标为(Xi,Yi),镇守这座城市的太守的能力值为Zi。
chnlich每次会选择一个边平行于坐标轴的矩形区域,并奇袭其中太守能力值第K小的城市(奇袭结束之后城市与太守依然存在)。
不过,他的敌人经常会偷偷交换两座城市的太守,防止弱点被chnlich发现。
现在,chnlich想要知道,每次奇袭时他的敌人的能力值。

$N \leq 6e4$

参考资料:

http://blog.csdn.net/hbhcy98/article/details/50642773

http://blog.csdn.net/braketbn/article/details/51187181

http://www.cnblogs.com/lazycal/archive/2013/08/05/3239304.html

https://www.cnblogs.com/rootial/p/3950105.html

https://www.cnblogs.com/candy99/p/6441989.html

技巧专题3(cdq分治、整体二分等)的更多相关文章

  1. 算法笔记--CDQ分治 && 整体二分

    参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...

  2. 一篇自己都看不懂的CDQ分治&整体二分学习笔记

    作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...

  3. Cdq分治整体二分学习记录

    这点东西前前后后拖了好几个星期才学会……还是自己太菜啊. Cdq分治的思想是:把问题序列分割成左右两个,先单独处理左边,再处理左边对右边的影响,再单独处理右边.这样可以消去数据结构上的一个log,降低 ...

  4. [学习笔记] CDQ分治&整体二分

    突然诈尸.png 这两个东西好像都是离线骗分大法... 不过其实这两个东西并不是一样的... 虽然代码长得比较像 CDQ分治 基本思想 其实CDQ分治的基本思想挺简单的... 大概思路就是长这样的: ...

  5. CDQ分治&整体二分学习个人小结

    目录 小结 CDQ分治 二维LIS 第一道裸题 bzoj1176 Mokia bzoj3262 陌上花开 bzoj 1790 矩形藏宝地 hdu5126四维偏序 P3157 [CQOI2011]动态逆 ...

  6. CQD(陈丹琦)分治 & 整体二分——专题小结

    整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料:       整体二分是个很神的东西 ...

  7. CDQ分治 & 整体分治

    Part 1:CDQ分治 CDQ分治讲解博客 可以把CDQ分治理解为类似与归并排序求逆序对个数的一种分治算法(至少我现在是这么想的).先处理完左右两边各自对答案的贡献,在处理跨越左右两边的对答案的贡献 ...

  8. luogu P5473 [NOI2019]I 君的探险 交互 随机 二分 分治 整体二分

    LINK:I 君的探险 神仙题! 考虑一个暴力的做法 每次点亮一个点 询问全部点 这样询问次数为 \(\frac{n\cdot (n-1)}{2}\) 可以通过前5个点. 考虑都为A的部分分 发现一个 ...

  9. CodeForces - 762E:Radio stations (CDQ分治||排序二分)

    In the lattice points of the coordinate line there are n radio stations, the i-th of which is descri ...

随机推荐

  1. What is python .. (“dot dot”) notation syntax?

    What you have is a float literal without the trailing zero, which you then access the __truediv__met ...

  2. Python中的HTMLParser、cookielib抓取和解析网页、从HTML文档中提取链接、图像、文本、Cookies(二)

    对搜索引擎.文件索引.文档转换.数据检索.站点备份或迁移等应用程序来说,经常用到对网页(即HTML文件)的解析处理.事实上,通过 Python语言提供的各种模块,我们无需借助Web服务器或者Web浏览 ...

  3. LUOGU P3047 [USACO12FEB]附近的牛Nearby Cows

    传送门 解题思路 树形dp,看到数据范围应该能想到是O(nk)级别的算法,进而就可以设出dp状态,dp[x][j]表示以x为根的子树,距离它为i的点的总和,第一遍dp首先自底向上,dp出每个节点的子树 ...

  4. 历届试题_DNA比对

    脱氧核糖核酸即常说的DNA,是一类带有遗传信息的生物大分子.它由4种主要的脱氧核苷酸(dAMP.dGMP.dCMT和dTMP)通过磷酸二酯键连接而成.这4种核苷酸可以分别记为:A.G.C.T.     ...

  5. http和tcp/ip,socket的区别

    http协议和tcp/ip协议乍看起来,感觉是同一类的东西,其实不然,下面简单的说说他们的区别. http协议是应用层的一种数据封装协议,类似的还有ftp,telnet等等,而tcp/ip是数据传输层 ...

  6. Python字符串切片操作知识详解

    Python字符串切片操作知识详解 这篇文章主要介绍了Python中字符串切片操作 的相关资料,需要的朋友可以参考下 一:取字符串中第几个字符 print "Hello"[0] 表 ...

  7. Maven实战错误笔记:使用mvn archetype:generate报错:Unable to add module to the current project as it is not of packaging type 'pom'

    在使用mvn archetype:generate生成Maven实战03:HelloWorld中的HelloWorld的项目骨架时报了这个错,从字面上分析是可能与pom.xml文件有关,然后我看了一下 ...

  8. Activiti实战01_认识Activiti

    什么是Activiti Activiti是为解决工作流而创建的一套流程引擎.举个最简单的例子,请假流程就是一个工作流,从开始到审批到结束,像流一样的贯穿整个流程.在工作中最常见的就是OA了.工作流总是 ...

  9. Docker(四)安装Redis

    1.安装redis https://blog.csdn.net/qq_29917523/article/details/78019511 2.测试连接

  10. Linux命令CURL用法

    Curl是一个命令行方式下传输数据的开源传输工具,支持多种协议包括:FTP,HTTP,HTTPS,IMAP,POP3,TELNET等.同样支持HTTP POST方法,PUT方法,FTP上传,cooki ...