【JZOJ6376】櫻符[完全墨染的櫻花]

description


analysis

  • 無向圖上任意兩點最大流不超過22,說明該圖是仙人掌

  • 由於最大流等於最小割,如果一條邊在兩個環裏,斷掉兩個端點至少需要33的代價

  • 對於該仙人掌,求兩點間的最小割,那麼要麼割一條橋邊,要麼割一個環上的兩條邊

  • 環上邊權最小邊一定要割,那就把這條邊斷開,環上其他邊邊權加上該邊邊權,相當於提前割

  • 然後圖就變成了一棵樹,任意兩點間最小割即爲路徑最小值

  • n1n-1條樹邊從大到小插入,這樣前面的不會影響到後面的貢獻

  • 並查集維護每一個集合的p(i1)n,pi\sum p^{(i-1)n},\sum p^i,由於分配律所以兩個集合的貢獻相乘就是整個集合的貢獻

  • 我一開始naivenaive認爲要用tarjantarjan縮環,打了才發現我還tootoo youngyoung

  • mm條邊降序排序後先直接構樹,記錄構成環的邊,然後找這些邊端點LCALCA,暴力把路徑上的邊權加上

  • 注意不要太過暴力,身經百戰後倍增也是很重要的


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 300005
#define MAXM 500005
#define ha 998244353
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=last[a];i;i=next[i])

using namespace std;

ll last[MAXM*2],next[MAXM*2],tov[MAXM*2],len[MAXM*2];
ll fa[MAXN],falen[MAXN],depth[MAXN];
ll sumin[MAXN],sumi[MAXN],anc[MAXN][20];
ll n,m,p,tot,ans,cnt;
bool bz[MAXN];

struct edge
{
	ll x,y,z;
}a[MAXM],b[MAXM];

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline ll max(ll x,ll y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline bool cmp(edge a,edge b){return a.z>b.z;}
inline ll getfa(ll x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline ll pow(ll x,ll y)
{
	ll z=1;
	while (y){if (y&1)z=z*x%ha;x=x*x%ha,y>>=1;}
	return z;
}
inline ll lca(ll x,ll y)
{
	if (depth[x]<depth[y])swap(x,y);
	fd(i,19,0)if (depth[anc[x][i]]>=depth[y])x=anc[x][i];
	if (x==y)return x;
	fd(i,19,0)if (anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
	return anc[x][0];
}
inline void link(ll x,ll y,ll z){next[++tot]=last[x],last[x]=tot,tov[tot]=y,len[tot]=z;}
inline void dfs(ll x,ll y)
{
	fo(i,1,19)anc[x][i]=anc[anc[x][i-1]][i-1];
	rep(i,x)if (tov[i]!=y)fa[tov[i]]=anc[tov[i]][0]=x,falen[tov[i]]=len[i],depth[tov[i]]=depth[x]+1,dfs(tov[i],x);
}
int main()
{
	freopen("T2.in","r",stdin);
	//freopen("sakura.in","r",stdin);
	//freopen("sakura.out","w",stdout);
	n=read(),m=read(),p=read();
	fo(i,1,n)fa[i]=i;
	fo(i,1,m)a[i].x=read(),a[i].y=read(),a[i].z=read();
	sort(a+1,a+m+1,cmp);
	fo(i,1,m)
	{
		ll x=a[i].x,y=a[i].y,z=a[i].z,xx=getfa(x),yy=getfa(y);
		if (xx!=yy)fa[xx]=yy,link(x,y,z),link(y,x,z);
		else b[++cnt].x=x,b[cnt].y=y,b[cnt].z=z;
	}
	depth[1]=1,dfs(1,0),tot=0;
	fo(i,1,cnt)
	{
		ll x=b[i].x,y=b[i].y,z=b[i].z,LCA=lca(x,y);
		if (LCA!=x){falen[x]+=z;while (fa[x]!=LCA)x=fa[x],falen[x]+=z;}
		if (LCA!=y){falen[y]+=z;while (fa[y]!=LCA)y=fa[y],falen[y]+=z;}
	}
	fo(i,2,n)a[++tot].x=i,a[tot].y=fa[i],a[tot].z=falen[i];
	sort(a+1,a+n,cmp);
	fo(i,1,n)sumin[i]=pow(p,(i-1)*n),sumi[i]=pow(p,i),fa[i]=i;
	fo(i,1,n-1)
	{
		ll x=a[i].x,y=a[i].y,z=a[i].z,xx=getfa(x),yy=getfa(y);
		(ans+=(z*sumin[xx]%ha*sumi[yy]%ha+z*sumin[yy]%ha*sumi[xx]%ha)%ha)%=ha;
		fa[xx]=yy,(sumin[yy]+=sumin[xx])%=ha,(sumi[yy]+=sumi[xx])%=ha;
	}
	printf("%lld\n",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章