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;
}

  

posted @ 2019-09-27 23:16  蒟蒻JHY  阅读(383)  评论(0编辑  收藏  举报