首页 > 其他分享 >CF1648E 题解

CF1648E 题解

时间:2023-08-16 16:44:27浏览次数:30  
标签:原图 sub CF1648E 题解 int 补图 blk mathcal

就是 \(m\) 组询问补图的最小生成树上的树链最大值。有两种基本思路求这棵树。

第一种,Kruskal,基于找到最小的边使两端点不连通。考虑补图中 \((x,y)\) 的边权,它是原图最小生成树上的树链最大值。从小到大枚举补图的边,相当于从小到大枚举原图最小生成树的边 \((u,v,w)\),然后:

令原图上,连接这条边之前,\(u\) 所在连通块为 \(S\),\(v\) 所在连通块为 \(T\),那么对于 \(x\in S,y\in T\),必然有补图中 \((x,y)\) 的边权恰为 \(w\)。当然这建立在补图中 \((x,y)\) 这条边存在的前提下。

所以直接模拟这个过程,暴力枚举 \(x\) 所在补图连通块 \(X\)(显然 \(X\subseteq S\)),然后不断地去寻找 \(y\) 所在补图连通块 \(Y(Y\subseteq T)\)。为了判断 \(X\) 与 \(Y\) 是否可以合并,枚举 \(x\in X\) 和 \(y\in T\),观察 \((x,y)\) 这条边在原图是否不存在即可。

四重循环。这个复杂度分三部分。其一,合并 \(X\) 与 \(Y\)。启发式合并即可总计 \(\mathcal O(n\log n)\)。

其二,寻找 \(Y\) 的过程中枚举 \(y\)。注意到每对 \((x,y)\) 至多枚举一次,\(y\) 会被跳过当且仅当原图存在边 \((x,y)\)。所以总共 \(\mathcal O(m)\)。

其三,合并 \(X\) 与 \(Y\) 的次数。显然是 \(\mathcal O(n)\)。

然后注意到判断 \((x,y)\) 原图是否有边是 \(\Theta(\log m)\) 的。于是令 \(m=\Omega(n)\) 则总复杂度 \(\mathcal O(m\log m)\)。这个应该是 CF 的 std。


第二种,Boruvka,基于对每个点找到离开所在连通块的最小边。对原图建出 Kruskal 重构树,补图中 \((x,y)\) 边权为 \(w_{\operatorname {lca(x,y)}}\)。

问题转化为,对于所有叶子结点 \(u\),找到其最深的祖先 \(a\),满足 \(a\) 的子树内存在一个 \(v\) 使得:

  • \(v\) 不在 \(u\) 的连通块内;

  • 原图中 \((u,v)\) 无边。

考虑连通块在重构树上形如一段 dfn 区间。合并连通块就是合并区间,同时子树也是一段 dfn 区间,于是二分一下即可找到 \(a\)。

对于原图无边这个限制,枚举 \(u\) 的所有 \(k\) 个出点,然后把查询区间暴力分成 \(\mathcal O(k)\) 个子段。这样一次 Boruvka 的过程只会查 \(\mathcal O(m)\) 个区间。

总复杂度 \(\mathcal O(n\log^2 n)\)。

个人写的是第一种思路。有点难调。

#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <cstring>

using namespace std;

namespace fIO{
	char c;void re(int &x){
		x=0;c=getchar();
		while(c<'0'||c>'9') c=getchar();
		while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	}
	char st[20];int tp;
	void wr(int n){
		while(n) st[++tp]=n%10+48,n/=10;
		while(tp) putchar(st[tp--]);
	}
}using fIO::re;using fIO::wr;

const int N=231231;

struct U{
	int anc[N];
	void set(int n){for(int i=1;i<=n;++i) anc[i]=i;}
	int qry(int x){return anc[x]==x?x:anc[x]=qry(anc[x]);}
	bool sam(int x,int y){return qry(x)==qry(y);}
	void mrg(int x,int y){anc[qry(x)]=qry(y);}
}O,B;

namespace AT{
	struct edg{int v,w;};
	vector<edg> vc[N];
	void lnk(int x,int y,int w){
		vc[x].push_back((edg){y,w});vc[y].push_back((edg){x,w});
	}
	int f[N][18],anc[N][18],dep[N];
	void build(int now,int lst){
		anc[now][0]=lst;dep[now]=dep[lst]+1;
		for(int i=1;(1<<i)<dep[now];++i) anc[now][i]=anc[anc[now][i-1]][i-1],
			f[now][i]=max(f[now][i-1],f[anc[now][i-1]][i-1]);
		for(auto[v,w]:vc[now]) if(v!=lst) f[v][0]=w,build(v,now);
	}
	int qry(int x,int y){
		int res=0;if(dep[x]<dep[y]) swap(x,y);
		for(int i=17;~i;--i) if((1<<i)<=dep[x]-dep[y])
			res=max(res,f[x][i]),x=anc[x][i];
		for(int i=17;~i;--i) if(anc[x][i]!=anc[y][i])
			res=max(res,max(f[x][i],f[y][i])),x=anc[x][i],y=anc[y][i];
		if(x!=y) res=max(res,max(f[x][0],f[y][0]));
		return res;
	}
	void clr(int n){
		for(int i=1;i<=n;++i) vc[i].clear(),memset(anc[i],0,sizeof(anc[i]));
	}
}

set<int> blk[N],sub[N];

int merg(int X,int Y){
	if(blk[X].size()>blk[Y].size()) swap(X,Y);
	for(int x:blk[X]) blk[Y].insert(x);
	return Y;
}

vector<int> vc[N],del;int pos[N];

void mrgsub(int &u,int &v,int w){
	if(sub[B.qry(u)].size()>sub[B.qry(v)].size()) swap(u,v);
	int pu=u,pv=v;u=B.qry(u);v=B.qry(v);
	for(int X:sub[u]){
		del.clear();int p=X;
		for(int Y:sub[v]){
			for(int x:blk[X]){
				bool flg=0;for(int y:blk[Y]){
					auto it=lower_bound(vc[x].begin(),vc[x].end(),y);
					if(it==vc[x].end()||*it!=y){
					flg=1;p=merg(p,Y);del.push_back(Y);AT::lnk(x,y,w);break;
				}}
				if(flg) break;
			}
		}
		for(int Y:del) sub[v].erase(Y);
		sub[v].insert(p);
	}
	B.mrg(u,v);u=pu;v=pv;
}

struct edg{int x,y,w,id;}e[N];

int ans[N];

int main()
{
	int T;re(T);while(T--){
		int n,m;re(n);re(m);O.set(n);B.set(n);AT::clr(n);
		for(int i=1;i<=n;++i) pos[i]=i,vc[i].clear(),
			sub[i].clear(),sub[i].insert(i),blk[i].clear(),blk[i].insert(i);
		for(int i=1;i<=m;++i) re(e[i].x),re(e[i].y),re(e[i].w),e[i].id=i,
			vc[e[i].x].push_back(e[i].y),vc[e[i].y].push_back(e[i].x);
		for(int i=1;i<=n;++i) sort(vc[i].begin(),vc[i].end());
		sort(e+1,e+m+1,[](edg u,edg v){return u.w<v.w;});
		for(int i=1;i<=m;++i) if(!O.sam(e[i].x,e[i].y))
			mrgsub(e[i].x,e[i].y,e[i].w),O.mrg(e[i].x,e[i].y);
		AT::build(1,0);
		for(int i=1;i<=m;++i) ans[e[i].id]=AT::qry(e[i].x,e[i].y);
		for(int i=1;i<=m;++i) wr(ans[i]),putchar(' ');puts("");
	}
}

标签:原图,sub,CF1648E,题解,int,补图,blk,mathcal
From: https://www.cnblogs.com/vanspace/p/cf1648e.html

相关文章

  • AT_agc064_a题解
    题面题目大意给定一个正整数\(N\),要求构造一个序列。对于每一个在\(1\)到\(N\)之间的整数\(i\),序列中包含了\(i\)个,并且将该序列首尾相接拼成环后,相邻两项之差大于等于\(1\)小于等于\(2\)。思路突破口是关于相邻两项之差的约束条件。(我一开始竟然只看见了“小于等......
  • CF1854D 题解
    CF1854DMichaelandHotel题解Links洛谷CodeforcesDescription这是一个交互题。有一个有\(n\)个点的内向基环树森林,zlsim位于\(1\)号节点,请你通过以下操作求出哪些节点(包括\(1\))可以通过从这两点开始沿边行走若干步汇至一点。给出两个参数\(u,k\)和点集\(S\),询......
  • P2034题解
    P2034题解题目描述给定一行\(n\)个非负整数\(a_1\cdotsa_n\)。现在你可以选择其中若干个数,但不能有超过\(k\)个连续的数字被选择。你的任务是使得选出的数字的和最大。题解正难则反,考虑将原问题转化为从\(a\)中选若干数使得,任意两数差不大于\(k\),求答案最小。观察......
  • ZS Shuffles Cards 题解
    ZSShufflesCards题解我们把每一次抽一些数字牌再抽到joker视作一局游戏。每局期望轮数首先考虑\(f_i\)表示每一局游戏抽出\(i\)张牌的概率。那么就是先抽出\(i-1\)张数字牌,再抽出一张joker。概率就是:\[f_i=\fracm{n+m-i+1}\prod_{k=0}^{i-2}......
  • CF1858A Buttons题解
    思路我们可以让两人先拿\(c\)里面的,因为\(a\)和\(b\)肯定是自己的,那么公共的“我”也要抢的越多越好,所以我们都要先拿\(c\)里面的。如果\(c\)是奇数,那么先手一定多拿\(1\)个\(c\)里面的,相当于先手可以拿\(a+1\)个,后手可以拿\(b\)个;如果\(c\)是偶数,那么两......
  • CF1858C Yet Another Permutation Problem 题解
    思路这个题是一个简单的构造题。竟然比T2简单,也是少见我们可以首先从\(1\)开始不断乘以\(2\),像这样:\(1,2,4,8,16\cdots,2^x\),直到什么时候超过\(n\)就停止。这样相邻两个数字就可以凑出\(1,2,4,6,\cdots,2^{x-1}\),保证两两不同。然后我们可以从\(3\)开始不......
  • 2023“钉耙编程”中国大学生算法设计超级联赛(9)- 1003 Reasoning 题解
    题目翻译基本符号有一推理系统,其中有这些符号:括号\((\)和\()\);逻辑连接词\(\lnot\)和\(\rightarrow\);全称量词\(\forall\);变量\(u\simz\);常量\(a\sime\);函数\(f\simh\);谓词\(P\simT\)。这些符号是构成系统的基础,他们之间能够组合出一些其他概念:项(term......
  • P3572题解
    P3572题解题面翻译有\(n\)棵树排成一排,第\(i\)棵树的高度是\(d_i\)。有\(q\)只鸟要从第\(1\)棵树到第\(n\)棵树。当第\(i\)只鸟在第\(j\)棵树时,它可以飞到第\(j+1,j+2,\cdots,j+k_i\)棵树。如果一只鸟飞到一颗高度大于等于当前树的树,那么它的劳累值会增......
  • CF1060E Sergey and Subway 题解
    题面由题意可知,在原图中经过边数为\(2\)的一对点,在新图中经过边数为\(1\)。所以每对点在新图中的距离为:\[\begin{aligned}\lceil\frac{dis(i,j)}{2}\rceil=\frac{dis(i,j)+dis(i,j)\;mod\;2}{2}\end{aligned}\]那么我们只需在原图上求出任意两点距离之和并加上\(dis......
  • 国标GB28181视频监控平台EasyGBS国标平台无法播放,抓包返回ICMP的问题解决方案
    国标GB28181视频平台EasyGBS是基于国标GB/T28181协议的行业内安防视频流媒体能力平台,可实现的视频功能包括:实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。国标GB28181视频监控平台部署简单、可拓展性强,支持将接入的视频流进行全终端、全平台分发,分发的......