技巧专题2(离散化、分块、数列差分化及前缀和)
离散化
每个元素范围很大但元素个数较少的情况。
条件:与数字之间的相对大小有关,而与具体是多少无直接联系。离线。
常见的应用是离散后放到数据结构里。
感觉全是数据结构题。。。(划掉,当然还有计算几何、分块一类的)
Line Painting
一个0~1e9的区间,初始都是白的,现进行N次操作,每次将一段区间图上一种颜色。最后求连续最长的白色区间。
Mayor's posters
n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。求出最后还能看见多少张海报。
程序自动分析
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设x1,x2,x3...代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:x1=x2,x2=x3,x3=x4,x4≠x1,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
$N \leq 1e5 , i,j \leq 1e9$
Ultra-QuickSort
给一些(n个)乱序的数,让你求冒泡排序需要交换数的次数
$ n \leq 500000 , a_i \leq 1e9 $
图形面积
桌面上放了N个平行于坐标轴的矩形,这N个矩形可能有互相覆盖的部分,求它们组成的图形的面积。
$N \leq 100 , |Xi|,|Yi| \leq 1e8 $
将所有的横线和竖线离散化排序,用它们将原矩形切分成一个个不重叠的小矩形,然后累计面积
分块
分块,就是将原序列处理成各个小块,目的是尽量地达到处理和询问之间的平衡
常用于:原本O(1)修改O(n)查询或O(n)修改O(1)查询优化成O(sqrt(n))修改O(sqrt(n))查询,或者看起来很像线段树(树状数组)但是又不好维护的。
有些专门卡空间的题可以用分块做(lca)。
能用分块就尽量不用树套树。
分块是一种思想,不一定按照序列分块,也可以按照值域分块、按照大小分块等。
教主的魔法
每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
$N \leq 1e6 , Q \leq 3000$
保证每块是排好序的,查找整块直接二分查找,然后散块暴力修改。 add标记,这样排好序之后查找的话就可以通过二分跳跃很大一部分查找
维护队列
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。
为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。
当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。
$N,M \leq 1e4$
对于每一个弹珠维护上一个弹珠的位置pre,分块,对每一块内pre排序。
hzwer的分块入门题5
给出一个长为n的数列,以及m个操作,操作涉及区间开方,区间求和。
hzwer的分块入门题8
给出一个长为n的数列,以及m个操作,操作涉及区间询问等于一个数c的元素,并将这个区间的所有元素改为c。
hzwer的分块入门题9
给出一个长为n的数列,以及m个操作,操作涉及询问区间的最小众数。
陈立杰区间众数解题报告:http://www.docin.com/p-679227660.html
大致思路:
如果不带修改:
1、定理 $mode(A \cup B) \in mode(A) \cup B$
2、基础算法
将数列分成sqrt(n)个块,预处理f[i][j]为从第i个块到第j个块的众数
对于询问的区间[l,r],如果l属于第a块,r属于第b块,a!=b。
那么把[l,r]分成3部分,1:l~a块最后一个; 2:a+1块~b-1块; 3:b块第一个~r
第2部分已经预先处理好,我们需要对 (第2部分的众数+第1部分所有数+第3部分所有数) 中的数查询在[l,r]出现了多少次(两种方法)。
每次询问复杂度sqrt(n)*logn,总复杂度(n+q)*sqrt(n)*logn。
3、优化
期望去掉log,查询一个数在[l,r]中出现次数O(1)
预处理C[i][x]表示前i个块中x出现多少次
预处理A[b][i][x]表示b块的前i个数中x出现多少次
因为一个块中不同的数最多为size=sqrt(n)个,所以C、A的空间复杂度都是n*sqrt(n)的。
对于A的处理我们还需要对每个块开一个表记录在这个块中每个数的id。
如果带修改:
有时间复杂度为 $ O ( (n+q) \times n^{ \frac{2}{3} } ) $的算法。
我们把序列分成$n^{\frac{1}{3}}$块。同样维护每对块之间的结果。
对于每对块之间,我们维护每个值出现了多少次和最大出现次数,同时记录出现了i次的值有多少个。
考虑询问,方法几乎不变,仍是前面预处理的办法,修改只会对C、A中sqrt(n)个数有影响。
Pig
红学姐和黄学长是好朋友。有一天,黄学长想吃猪肉丸,于是他去找红学姐买猪。红学姐到她的猪圈中赶猪的时候发现有许多猪逃离了她的猪圈。
同时红学姐发现,一个名叫wwf的魔法猪藏在某个猪圈中施法。
为了确定wwf的位置,方老师向红学姐提出了m组询问,每次询问标号在区间[l,r]内的猪圈剩余的猪的数量和。
猪圈中猪的数量可能是负数。
空间限制:3M
$n,m \leq 500000,|x[i]| \leq 8000000$
Solar Panels
给定A,B,C,D,求满足A≤x≤B&&C≤y≤D的gcd(x,y)的最大值
#include<iostream> #include<cstdio> using namespace std; void doit() { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); a--;c--; int i,j,x,y,ans; int aa,bb,cc,dd; if(d>b) swap(b,d),swap(a,c); for(i=1;i<=d;i=j+1) { j=min(b/(b/i),d/(d/i)); if(i<=a) j=min(j,a/(a/i)); if(i<=c) j=min(j,c/(c/i)); if(b/i>a/i&&d/i>c/i) ans=j; } printf("%d\n",ans); } int main() { int T; scanf("%d",&T); while(T--) doit(); }
[Hnoi2016]最小公倍数
给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值。所有权值都可以分解成2^a*3^b的形式。
现在有q个询问,每次询问给定四个参数u、v、a和b,请你求出是否存在一条顶点u到v之间的路径,使得路径依次经过的边上的权值的最小公倍数为2^a*3^b。
注意:路径可以不是简单路径。
$n,q \leq 50000 , m \leq 100000$
把边按照a每sqrt(m)分一组,然后把询问按b排序, 把在这组及以前的边按b排序把这些边用并查集一条一条插入并维护。 零散的部分暴力插入并记录,做完后暴力撤销注意:并查集不能路径压缩,否则无法撤销回去
loj6046爷
给你一个 n 个点的有根树,1 为根,带边权,有 m 次操作。
1 求 x 的子树中第 k 小的深度的值,如果子树中没有 k 个点则输出 -1;
2 将 x 与 x 父亲的边权加上 k。
保证每次操作 2 的 k 以及原树的边权小于等于一个数 len。
如果操作 2 中 x 为 1 ,那么视为将 x 的基础深度加上了 k 。
分块,每隔一段时间重新暴力分块,如果块大小>size或者块内极小值极大值差>S,就重分一块。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<ctime> #include<set> using namespace std; #define ll long long #define db double #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) const int maxn=2e5+7,maxt=1000+7,maxs=2e4+7,S=2e3,INF=0x3f3f3f3f; int n,m,len,a[maxn],bel[maxn],sz; int L[maxn],R[maxn]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxn],to[maxn],e=0,v[maxn]; void add(int x,int y,int z) { to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z; } int dfn[maxn],fed[maxn],dfn_clock; void dfs(int pos,int d) { dfn[pos]=++dfn_clock; a[dfn_clock]=d; for(int y=fir[pos];y;y=nxt[y]) dfs(to[y],d+v[y]); fed[pos]=dfn_clock; } int sum[maxt][maxs],pl[maxt],pr[maxt],tot; int d[maxn]; inline void pd(int x) { if(!d[x]) return; For(i,L[x],R[x]) a[i]+=d[x]; d[x]=0; } inline void ud(int x) { pl[x]=INF; pr[x]=-INF; For(j,L[x],R[x]) { pl[x]=min(pl[x],a[j]); pr[x]=max(pr[x],a[j]); } For(j,0,pr[x]-pl[x]) sum[x][j]=0; For(j,L[x],R[x]) ++sum[x][a[j]-pl[x]]; For(j,1,pr[x]-pl[x]) sum[x][j]+=sum[x][j-1]; } void bld() { For(i,1,tot) pd(i); int now=1,ld=INF,rd=-INF; L[1]=1; For(i,1,n) { ld=min(ld,a[i]); rd=max(rd,a[i]); if(rd-ld>S||i-L[now]>=sz) { R[now]=i-1; L[++now]=i; ld=rd=a[i]; } R[bel[i]=now]=i; } tot=now; For(i,1,tot) ud(i); } inline int get_sum(int p,int x) { if(x<pl[p]) return 0; if(x>pr[p]) return sum[p][pr[p]-pl[p]]; return sum[p][x-pl[p]]; } inline int q(int ld,int rd,int x) { int rs=0,lt=bel[ld],rt=bel[rd]; if(lt==rt) { For(i,ld,rd) if(a[i]<=x) ++rs; return rs; } if(ld!=L[lt]) {For(i,ld,R[lt]) if(a[i]<=x) ++rs;} else rs+=get_sum(lt,x); if(rd!=R[rt]) {For(i,L[rt],rd) if(a[i]<=x) ++rs;} else rs+=get_sum(rt,x); For(i,lt+1,rt-1) rs+=get_sum(i,x); return rs; } inline int Yth(int ld,int rd,int k) { int lt=bel[ld],rt=bel[rd]; pd(lt); pd(rt); if(rd-ld+1<k) return -1; int l=INF,r=-INF,mid; For(i,lt,rt) l=min(l,pl[i]),r=max(r,pr[i]); if(l==r) return l; --l; while(l<r-1) { mid=(l+r)>>1; if(q(ld,rd,mid)>=k) r=mid; else l=mid; } return r; } inline void chge(int ld,int rd,int x) { int lt=bel[ld],rt=bel[rd]; if(lt==rt) { pd(lt); For(i,ld,rd) a[i]+=x; ud(lt); return; } if(ld!=L[lt]) { pd(lt); For(i,ld,R[lt]) a[i]+=x; ud(lt); } else d[lt]+=x,pl[lt]+=x,pr[lt]+=x; if(rd!=R[rt]) { pd(rt); For(i,L[rt],rd) a[i]+=x; ud(rt); } else d[rt]+=x,pl[rt]+=x,pr[rt]+=x; For(i,lt+1,rt-1) d[i]+=x,pl[i]+=x,pr[i]+=x; } int main() { read(n); read(m); read(len); sz=300; int op,x,y; For(i,2,n) { read(x); read(y); add(x,i,y); } dfs(1,0); bld(); For(i,1,m) { read(op); read(x); read(y); if(op==1) printf("%d\n",Yth(dfn[x],fed[x],y)); else chge(dfn[x],fed[x],y); if(i%1000==0) bld(); } return 0; }
作诗(zuosi)
N个数,M组询问,每次问[l,r]中有多少个数出现正偶数次。
$n,m,c \leq 1e5$
预处理F[i][j]表示第i块到第j块的答案。 一个询问l-r,那么中间大块x-y的答案已经得到了只要考虑l-x和y-r对答案的影响, 对于这里面每个数统计它在x-y出现次数t1,以及l-r出现次数t2, 根据t1,t2的奇偶性考虑其对答案的影响 每块大小sqrt(n/logn),复杂度n sqrt(n logn)
莫队
适用范围:离线、查询较多、从[l,r]转移到[l-1,r]或[l+1,r]或[l,r-1]或[l,r+1]比较快(一般为O(1)或O(logn))。
一般分为3种:普通莫队、带修莫队、树上莫队(wjx讲)。
优雅的暴力。
由于只维护当前状态的信息,所以空间也比较小,一般不需要维护一大堆前缀信息或者各种区间信息乱搞。
把每个询问看作是二维平面上的点,那么我们的最小总时间,就是这些点的最小曼哈顿距离生成树, 按照这个树的顺序做,复杂度O(n*sqrt(n))
但是为了简便一般直接分块。
假如有2维,按照第一维分块,每块里面按照另一维排序。这个时候一般每块大小sqrt(n)较优。
假如有3维(带修改,加上时间这一维),每块里面将第二维作为第1关键字,把第三维作为第2关键字排序。这时候一般每块大小$n^{ \frac{2}{3} }$较优。
块的最优大小根据数据的特点而改变(这就叫玄学)。
sb题1:给出一个长为n的数列,以及m个操作,操作涉及询问区间的最小众数。不强制在线。
sb题2:n个数,m次询问,每次问[l,r]区间有多少个数恰好出现正偶数次。不强制在线。
Mato的文件管理
Mato同学从各路神犇以各种方式收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号。
Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料。他总是从文件大小从小到大看资料。
他先把要看的文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序。
排序程序可以在1单位时间内交换2个相邻的文件(因为加密需要,不能随机访问)。
Mato想要使文件交换次数最小,你能告诉他每天需要交换多少次吗?
$n,q \leq 5e4$
XOR and Favorite Number
给你一个长度为n的数列和m个询问,问区间中多少连续子区间满足异或和为k。
$n,m \leq 1e5 , a[x] \leq 1e6$
回滚莫队:用于处理难以删除但是易于添加(其实易于删除难以添加也可以)的莫队,排序照常,
如果左右端点在同一块直接暴力,这部分最多n sqrt n,
否则把左端点在一块的一起处理,清空莫队,然后直接令莫队左端点在块尾,这部分n sqrtn,
右端点照常走,这部分n sqrtn ,左端点每次走的时候记录更改了哪些量,
走到地方记录完答案把修改回滚回去,这部分也是n sqrtn.
历史研究
有一个长度为N的序列。
有Q个询问,每次询问l~r范围内每个数值乘以该数值出现次数的最大值。
$N \leq 1e5 , Q \leq 1e5 , X_i \leq 1e9 $
数列差分化及前缀和
树状数组区间查询区间修改
金发姑娘和N头牛
第i头奶牛必须在指定的温度范围内A(i)..B(i)才感觉舒适(0<=A(i)<=B(i)<= 1,000,000,000)。
如果金发姑娘在谷仓放置一个温控器;如果温度T<A(i),牛会太冷,并将产生x单位牛奶。
如果她把恒温器调到(A(i)<=T<=B(i))这个范围内,那么牛会感到舒适,并将产生Y单位牛奶。
如果她把恒温器调到温度T>B(i),牛会感觉很热,并将产生的Z单位牛奶。
正如预期的那样,Y的值总是大于X和Z。给定的X,Y,和Z,以及每个牛的温度的最佳范围,如果金发姑娘设置谷仓的温控器最佳,请计算金发姑娘得到牛奶的最大数量。
已知X,Y和Z都是整数,范围0..1000。温控器可以设置为任意整数的值。
$N \leq 2e4$
把三个区间进行差分。把A、B离散、排序。就把问题转化成了最大前缀和问题。
借教室
我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。
共有m份订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示某租借者需要从第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj个教室。
我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。
如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。
现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单 。
$n,m \leq 1e6$
中位数图
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。
$n \leq 1e5$
Balanced Lineup
Farmer John 决定给他的奶牛们照一张合影,他让 N (1 ≤ N ≤ 50,000) 头奶牛站成一条直线,每头牛都有它的坐标(范围: 0..1,000,000,000)和种族(0或1)。
他只给一部分牛照相,并且这一组牛的阵容必须是“平衡的”。平衡的阵容,指的是在一组牛中,种族0和种族1的牛的数量相等。
请算出最广阔的区间,使这个区间内的牛阵容平衡。区间的大小为区间内最右边的牛的坐标减去最做边的牛的坐标。
保证每个种族至少有一头牛,没有两头牛的坐标相同。
JOIOJI
给一个只由JOI三个字母组成的串,求最长的一个子串使其中JOI三个字母出现次数相等。
$len \leq 2e5$
树上差分
将路径上的所有点权值加一,求最后点的权值。找被所有路径共同覆盖的边。
似乎noip很喜欢考。
天天爱跑步?
运输计划
L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。
显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。
当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?
$n \leq 3e5$
大都市
乡下有依次编号为1..n的n个小村庄,某些村庄之间有一些双向的土路,这些土路构成了一棵树。
Blue Mary从比特堡(根)出发,需要去某个村庄,并且在两次送信经历的间隔期间,有某些土路被改造成了公路.
请你计算出每次送信她需要走过的土路数目。
A a b(1 <= a < b <= n),表示将a到b的土路修为公路
W a, 则表示Blue Mary从比特堡送信到村庄a。
保证父亲一定比儿子编号小。
$n \leq 250000$
部落冲突
有n个部落他们连城一棵树。处理下面三件事,所有的事件都是按照时间顺序给出的。
1.(Q p q)从第 p 个部落出发的建筑工人想知道能否到达第 q 个部落了,你要回答的便是(Yes/No)
2.(C p q)第 p 个部落与第 q 个部落开战了,保证他们一定是相邻的部落
3.(U x ) 第 x 次发生的战争结束了,它将永远的被载入史册,不复存在
$n \leq 3e5$
参考资料:
https://www.cnblogs.com/SilverNebula/p/6035335.html
http://blog.csdn.net/keshuai19940722/article/details/40410293
http://blog.csdn.net/non_cease/article/details/7383736
http://www.cnblogs.com/BeyondW/p/5908139.html
http://hzwer.com/8053.html
http://hzwer.com/2793.html
http://blog.csdn.net/thy_asdf/article/details/51203421
http://hzwer.com/3663.html
http://www.docin.com/p-679227660.html
http://blog.csdn.net/hzj1054689699/article/details/51866615
https://www.cnblogs.com/Rivendell/p/4141406.html
http://blog.csdn.net/mc_dl/article/details/78408758
http://blog.csdn.net/MaverickFW/article/details/72988286