题解:Many Many Cycles
前言
好题。
第一次听说切边等价。
思路分析
首先玩两个环的情况。令环长分别为 \(c_1,c_2\),重合部分的长度为 \(s\),那么答案为:
\[\gcd(c_1,c_2,c_1+c_2-2s)=\gcd(c_1,c_2,2s)
\]
对于大于两个环的情况,我们可以任意拆解成两个环的情况,再进行计算。
因此,我们只需要找出若干个简单环,以及它们的切边等价类,按题意取 \(gcd\) 即可。
实现上,可以找出原图的一个生成森林,对于每个由一条非树边构成的环,我们求出环长,同时用树上差分异或哈希维护切边等价类,也就是若干环的极大共同重合部分,因为需要求 lca,所以复杂度为 \(O(n \log n)\)。
代码实现
注意特判只有一个环的等价类,它们不属于环的重合部分,不应该被统计到答案里。
#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;
}

浙公网安备 33010602011771号