zoukankan      html  css  js  c++  java
  • 【JZOJ6376】樱符[完全墨染的樱花]

    description


    analysis

    • 无向图上任意两点最大流不超过(2),说明该图是仙人掌

    • 由于最大流等于最小割,如果一条边在两个环里,断掉两个端点至少需要(3)的代价

    • 对于该仙人掌,求两点间的最小割,那么要么割一条桥边,要么割一个环上的两条边

    • 环上边权最小边一定要割,那就把这条边断开,环上其他边边权加上该边边权,相当于提前割

    • 然后图就变成了一棵树,任意两点间最小割即为路径最小值

    • (n-1)条树边从大到小插入,这样前面的不会影响到后面的贡献

    • 并查集维护每一个集合的(sum p^{(i-1)n},sum p^i),由于分配律所以两个集合的贡献相乘就是整个集合的贡献

    • 我一开始(naive)认为要用(tarjan)缩环,打了才发现我还(too) (young)

    • (m)条边降序排序后先直接构树,记录构成环的边,然后找这些边端点(LCA),暴力把路径上的边权加上

    • 注意不要太过暴力,身经百战后倍增也是很重要的


    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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    PHP与WCF第一次亲密接触
    PHP操作MongoDB
    如何用SVN进行个人版本管理
    【Android】还原“微信”apk中的“发现”和“我”两个模块
    使php支持mbstring库
    mysql 与 mysqli的区别
    nginx 配置正向 HTTP 代理服务器[转]
    正向代理与反向代理的区别【Nginx读书笔记】
    为什么要使用Nginx?
    【转】关于HTTP中文翻译的讨论
  • 原文地址:https://www.cnblogs.com/horizonwd/p/11628440.html
Copyright © 2011-2022 走看看