#4637. 樱符「完全墨染的樱花」
题目描述
暂无
数据范围
暂无
题解
考虑到这张图是仙人掌,即一条边最多属于一个简单环。
要求两点间的最大流,即求最小割,那要割的要么是桥边,要么是两条环边。
考虑到如果删去的是环边的话,那一定会删掉边权最小的边。
所以可以把每个环的最小的边删去,同时其他边加上这条边的权值,这样两点间的最小割不会改变,进而只要求一棵树的两点间的最小割即可。
所以用并查集维护即可。
代码
#include <bits/stdc++.h> using namespace std; const int N=1e6+5,P=998244353; int n,m,p,t,hd[N],V[N],nx[N],W[N],f[N]; int a[N],b[N],fa[N],d[N],g[N],Q,ans,G; bool vis[N];struct E{int u,v,w;}e[N],q[N]; bool cmp(E A,E B){return A.w>B.w;} int get(int x){ return f[x]==x?x:f[x]=get(f[x]); } int X(int x){return x>=P?x-P:x;} int K(int x,int y){ int z=1; for (;y;y>>=1,x=1ll*x*x%P) if (y&1) z=1ll*z*x%P; return z; } void add(int u,int v,int i){ nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=i; } void dfs(int u,int fr){ d[u]=d[fa[u]=fr]+1; for (int i=hd[u];i;i=nx[i]) if (V[i]!=fr) g[V[i]]=W[i],dfs(V[i],u); } int main(){ cin>>n>>m>>p; for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+m+1,cmp); for (int i=1;i<=n;i++) f[i]=i; for (int u,v,i=1;i<=m;i++){ u=get(e[i].u);v=get(e[i].v); if (u==v) q[++Q]=e[i]; else add(e[i].u,e[i].v,i), add(e[i].v,e[i].u,i),f[v]=u; } dfs(1,0); for (int u,v,i=1;i<=Q;i++){ u=q[i].u;v=q[i].v; if (d[u]<d[v]) swap(u,v); while(d[u]>d[v]) e[g[u]].w+=q[i].w,u=fa[u]; while(u!=v) e[g[u]].w+=q[i].w,u=fa[u], e[g[v]].w+=q[i].w,v=fa[v]; } sort(e+1,e+m+1,cmp); for (int i=1;i<=n;i++) f[i]=i,a[i]=K(p,i),b[i]=K(p,1ll*(i-1)*n%(P-1)); for (int u,v,i=1;i<=m;i++){ u=get(e[i].u);v=get(e[i].v);if (u==v) continue; ans=X(ans+1ll*(1ll*a[u]*b[v]%P+1ll*a[v]*b[u]%P)*e[i].w%P); a[u]=X(a[u]+a[v]);b[u]=X(b[u]+b[v]);f[v]=u; } printf("%d\n",ans);return 0; }