Codeforces 1220 E Tourism
可以发现一个边双必然是可以随意走的,所以我们就把原图求割边然后把边双缩成一个点,然后就是一个树上dp了。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=200005; #define pb push_back inline int read(){ int x=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x; } vector<int> G[N]; int n,a[N],dfn[N],low[N],lt[N],k,siz[N]; int hd[N],ne[N*2],to[N*2],num=1,tot[N],dc,m,s; ll ltw[N],ans,M,mx[N]; bool ban[N*2]; inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num; } void dfs(int x,int fa){ dfn[x]=low[x]=++dc; for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa) if(!dfn[to[i]]){ dfs(to[i],x),low[x]=min(low[x],low[to[i]]); if(low[to[i]]>=dfn[to[i]]) ban[i]=ban[i^1]=1; } else low[x]=min(low[x],dfn[to[i]]); } void B(int x){ lt[x]=k,ltw[k]+=a[x],siz[k]++; for(int i=hd[x];i;i=ne[i]) if(!ban[i]&&!lt[to[i]]) B(to[i]); } void dp(int x,int fa){ tot[x]=siz[x]>1; for(int i:G[x]) if(i!=fa){ dp(i,x),tot[x]+=tot[i],mx[x]=max(mx[x],mx[i]); } mx[x]+=ltw[x]; if(tot[x]) ans+=ltw[x]; else M=max(M,mx[x]); } inline void solve(){ for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,i); for(int i=1;i<=n;i++) if(!lt[i]) k++,B(i); for(int i=1;i<=n;i++) for(int j=hd[i];j;j=ne[j]) if(lt[i]!=lt[to[j]]) G[lt[i]].pb(lt[to[j]]); dp(lt[s],0); ans+=M; } inline void check(){ cout<<k<<' '<<lt[s]<<endl; for(int i=1;i<=k;i++){ cout<<i<<"'s size is"<<siz[i]<<endl; for(int j:G[i]) cout<<j<<" "; cout<<endl; } } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1,u,v;i<=m;i++) u=read(),v=read(),add(u,v),add(v,u); s=read(),solve(); cout<<ans<<endl; // check(); return 0; }
我爱学习,学习使我快乐