人,只有自己站起来,这个世界才能属于他。|

园龄:粉丝:关注:

题解:Many Many Cycles

前言

好题。

第一次听说切边等价。

思路分析

首先玩两个环的情况。令环长分别为 c1,c2,重合部分的长度为 s,那么答案为:

gcd(c1,c2,c1+c22s)=gcd(c1,c2,2s)

对于大于两个环的情况,我们可以任意拆解成两个环的情况,再进行计算。

因此,我们只需要找出若干个简单环,以及它们的切边等价类,按题意取 gcd 即可。

实现上,可以找出原图的一个生成森林,对于每个由一条非树边构成的环,我们求出环长,同时用树上差分异或哈希维护切边等价类,也就是若干环的极大共同重合部分,因为需要求 lca,所以复杂度为 O(nlogn)

代码实现

注意特判只有一个环的等价类,它们不属于环的重合部分,不应该被统计到答案里。

#include<bits/stdc++.h>
#define int long long
using namespace std;
mt19937 rnd(time(0));
int n,m,gcd,c[10005],d[10005],h[10005],x[10005],y[10005],w[10005],e[10005],vis[10005];
int fa[5005],num[5005];
void init(){
	for(int i=1;i<=n;i++){
		fa[i]=i;
		num[i]=h[i];
	}
}
int find(int x){
	if(fa[x]==x) return x;
	else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y) return;
	fa[x]=y;
	num[y]+=num[x];
}
int head[5005],nxt[20005],targetx[20005],targetw[200005],tot;
void add(int x,int y,int w){
	tot++;
	nxt[tot]=head[x];
	head[x]=tot;
	targetx[tot]=y;
	targetw[tot]=w;
}
int siz[5005],dep[5005],dfn[5005],dis[5005],rnk[5005],top[5005],hson[5005],f[5005],cnt;
void dfs1(int x,int fa){
	siz[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=targetx[i],w=targetw[i];
		if(y==fa) continue;
		dep[y]=dep[x]+1;
		dis[y]=dis[x]+w;
		f[y]=x;
		h[y]=w;
		dfs1(y,x);
		siz[x]+=siz[y];
		if(siz[hson[x]]<siz[y]) hson[x]=y;
	}
}
void dfs2(int x,int t){
	top[x]=t;
	cnt++;
	dfn[x]=cnt;
	rnk[cnt]=x;
	if(!hson[x]) return;
	dfs2(hson[x],t);
	for(int i=head[x];i;i=nxt[i]){
		int y=targetx[i],w=targetw[i];
		if(y==f[x] || y==hson[x]) continue;
		dfs2(y,y);
	}
}
int lca(int x,int y){
	while(top[x]^top[y]){
		if(dep[top[x]]>dep[top[y]]) x=f[top[x]];
		else y=f[top[y]];
	}
	if(dfn[x]<dfn[y]) return x;
	else return y;
}
void dfs3(int x,int fa){
	vis[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=targetx[i];
		if(y==fa) continue;
		dfs3(y,x);
		c[x]^=c[y];
		d[x]+=d[y];
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	init();
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i]>>w[i];
		e[i]=rnd();
		if(find(x[i])!=find(y[i])){
			add(x[i],y[i],w[i]);
			add(y[i],x[i],w[i]);
			merge(x[i],y[i]);
		}else{
			vis[i]=1;
		}
	}
	for(int i=1;i<=n;i++){
		if(!siz[i]){
			dfs1(i,0);
			dfs2(i,i);
		}
	}
	for(int i=1;i<=m;i++){
		if(vis[i]){
			gcd=__gcd(gcd,dis[x[i]]+dis[y[i]]-2*dis[lca(x[i],y[i])]+w[i]);
			c[x[i]]^=e[i];
			c[y[i]]^=e[i];
			d[x[i]]++;
			d[y[i]]++;
			d[lca(x[i],y[i])]-=2;
		}
	}
	for(int i=1;i<=n;i++){
		vis[i]=0;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			dfs3(i,0);
		}
	}
	init();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(c[i]==c[j]) merge(i,j);
		}
	}
	for(int i=1;i<=n;i++){
		if(d[i]>=2 && find(i)==i) gcd=__gcd(gcd,num[i]<<1);
	}
	cout<<gcd;
	return 0;
}

本文作者:Kenma

本文链接:https://www.cnblogs.com/Kenma/p/18698586

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Kenma  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起