做题记录

Luogu4180 【模板】严格次小生成树[BJWC2010]

Link
结论:有至少一棵次小生成树,和最小生成树只有一条边的差异。非严格的次小生成树可以在求出最小生成树之后,枚举未选的边,用它替代覆盖的路径上的最大边即可。但是题目要求严格次小,所以再记录一下路径上的严格次大边,如果枚举到的边不大于最大边,就替代次大边。
直接lca+倍增就行。用LCT也是可以的。不过LCT常数极大,加了暗黑优化才过kk。

Luogu4234 最小差值生成树

Link

把边从大到小排序。每次枚举一条边,如果两端点未联通,就直接加上。

如果已联通,肯定是贪心地把覆盖路径上最小的边给替换掉。因为从小到大枚举,所以最大边是枚举的这条边,最小边用一个全局指针维护。如果当前已经是一棵生成树(开个变量记录加入的边数即可),就可以用最大边减去最小边了更新答案。

注意LCT维护边的信息是通过化边成点的方式。即新增一个点,夹在两端点之间,点权是原边权。

Luogu4822 [BJWC2012]冻结

Link

分层图最短路。单独一层边权不变,上下两层用原边权的二分之一连接。统计答案时在各层第n个点代价中取min。理性分析一下,层与层之间的边对应的原边(可以减少代价的边)在全图中不会用超过一次。

Luogu4172 [WC2006]水管局长

Link

题目要求动态维护最小生成树。但是有删边操作,这就很不好处理。考虑倒着处理询问,原来的删边变成了加边,就很好维护了。

Luogu2173 [ZJOI2012]网络

Link

开C棵LCT,分别维护各自颜色的森林就行了。操作都是LCT的基本操作。

Luogu2147 [SDOI2008]洞穴勘测

Link

LCT维护联通性。

Luogu3203 [HNOI2010]弹飞绵羊

Link

(i)个装置和第(i+k_i)个装置连接一条边(第(i+k_i)做父亲)。LCT维护的是一个森林。这样查询就是到根节点路径长度。直接(access(x),splay(x)),输出(x)(size)

Luogu1501 [国家集训队]Tree II

Link

维护乘法和加法,可以借鉴Luogu3373 【模板】线段树 2的方法。

inline void pushmul(int x,int c){times(s[x],c),times(mul[x],c),times(v[x],c),times(pls[x],c);}
inline void pushpls(int x,int c){add(s[x],1ll*siz[x]*c%mod),add(v[x],c),add(pls[x],c);}
inline void pushdown(int x){
	if(r[x])pushr(ch[x][0]),pushr(ch[x][1]),r[x]=0;
	if(mul[x]^1)pushmul(ch[x][0],mul[x]),pushmul(ch[x][1],mul[x]),mul[x]=1;
	if(pls[x])pushpls(ch[x][0],pls[x]),pushpls(ch[x][1],pls[x]),pls[x]=0;
}

pushdown时先乘后加。区间乘包括加法标记都要乘上。因为是LCT维护,所以区间加的时候还要知道子树大小siz[x]。pushup还需要用到单点值v[x]。

Luogu3950 部落冲突

Link
LCT维护联通性。

Luogu1505 [国家集训队]旅游

Link

为什么题单里面全是水题板子题啊,我都要做吐了。

不过这道题有个坑的是要记得初始化,因为他既询问min又询问max。而且初始化要从0开始!!!!然后pushup也要判断是不是边拆成的虚点。不是就不能用(v[x])更新。

Luogu2486 [SDOI2011]染色

Link

(LCT)板子题。(splay)上每个点的子树是原树的一条链,整个(splay)就是整条实链。所以可以记(L[],R[])表示链首和链尾的颜色,(tot)表示颜色段数,合并时讨论一下左右儿子的情况。

inline void pushup(int x){
		L[x]=ch[x][0]?L[ch[x][0]]:c[x];R[x]=ch[x][1]?R[ch[x][1]]:c[x];
		if(ch[x][0]&&ch[x][1])s[x]=s[ch[x][0]]+s[ch[x][1]]+1-(c[x]==R[ch[x][0]])-(c[x]==L[ch[x][1]]);
		else if(ch[x][0])s[x]=s[ch[x][0]]+1-(c[x]==R[ch[x][0]]);
		else if(ch[x][1])s[x]=s[ch[x][1]]+1-(c[x]==L[ch[x][1]]);
		else s[x]=1;
	}

Luogu4546 [THUWC2017]在美妙的数学王国中畅游

Link

就是(LCT)维护点权和。只是普通的是直接读入点权,这个要泰勒展开一下,然后维护各项系数和。直接带(x_0=0)很方便。考虑精度问题函数取12项就够了。

Loj2006 [SCOI2015]小凸玩矩阵

Link

显然二分。但是第(k)大不好做,转化成第(n-k+1)小。所以就变成了判断能否找到(n-k+1)个小于(mid)的值行列都不同。将矩阵上不超过(mid)的点看做1,跑最大匹配。

套路地建图:每行每列建虚点,行和(s)相连,列和(t)相连,矩阵上((i,j))有点就把行(i)和列(j)连接。边容量都是1。

CF1023F Mobile Phone Network

Link

先强制我的边都在最小生成树上,这样构造出一棵最小生成树。对于对手不在生成树上的边,其覆盖的路径上每一条边都要小于等于它的边权,所以是个链上取(min)的操作。

考虑具体做法。因为是取(min),如果把操作序列按边权从小到大排列,那就变成了区间覆盖问题。如果树上某条边已经被覆盖过了,以后就不会再覆盖。所以可以用并查集维护每个点向上已经覆盖到何处,每次直接在并查集暴跳即可。因为每条边只会被覆盖一次,所以复杂度是( ext O(n))的。

还有一种倍增的做法。对于每条边,他覆盖的((x,y))的链分成((x,lca))((y,lca)),按照平时倍增的思路步子从大到小跳,进行取min操作。然后全部做完更新答案时,将平时倍增的更新反着做一遍。

for(int j=6;j>=0;--j)
		for(int i=1;i<=n;++i)
				Min(mn[i][j],mn[i][j+1]),Min(mn[fa[i][j]][j],mn[i][j+1]);

BZOJ3691 游行

将两个限制转化一下,成环或把两个联通块连接,减少的代价都是(C)

因为(C)是变化的,就先考虑计算没有(C)的部分。

没有(C)的部分是一个最小可重路径覆盖。(Floyd)求出任意两点之间最短路径,转化成最小不重路径覆盖就可以直接做了。

考虑到费用流每次增广花费是递增的,所以每次询问我们可以二分找到一个时间点(p),在他之前的增广都小于等于(C),之后的都大于(C)(p)之前的用增广的费用,之后直接用((n-p)*C)补上。

原文地址:https://www.cnblogs.com/fruitea/p/12112965.html