题面
题意
给出一幅有n个点,n条边的无向未必联通图,每一个点有一个权并与另外一个点相连,对其中一些点进行染色,且相邻两点的颜色不能都染,则最大的染色点权值和是多少.
分析
这题和 洛谷P1453城市环路 很像,区别就在于它不是连通图.
因而可以先用并查集和vector进行分块,易证每一块都是比树多一条边的连通图,每一块再按照洛谷 P1453 城市环路的做法做即可.
代码
//#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 1001000
#define db double
#define ll long long
using namespace std;
struct Bn
{
ll next,to;
};
Bn bn[N*2];
ll n,ans,an,zl[N],bb,first[N],s,t,dp[N][2],fa[N],j1,j2;
bool vis[N],get;
vector<int>jh[N];
inline void add(ll u,ll v)
{
bb++;
bn[bb].next=first[u];
bn[bb].to=v;
first[u]=bb;
}
void find(ll now,ll last)
{
if(get) return;
ll p=first[now];
for(; p!=-1; p=bn[p].next)
{
if(bn[p].to==last) continue;
if(vis[bn[p].to])
{
s=now;
t=bn[p].to;
get=1;
return;
}
vis[bn[p].to]=1;
find(bn[p].to,now);
}
}
ll dfs(ll now,bool rs,ll last)
{
if(dp[now][rs]!=-1) return dp[now][rs];
ll i,j,res=0,p=first[now];
if(rs)
{
for(; p!=-1; p=bn[p].next)
{
if(bn[p].to==last||p==j1||p==j2) continue;
res+=dfs(bn[p].to,0,now);
}
}
else
{
for(; p!=-1; p=bn[p].next)
{
if(bn[p].to==last||p==j1||p==j2) continue;
res+=max(dfs(bn[p].to,0,now),dfs(bn[p].to,1,now)+zl[bn[p].to]);
}
}
dp[now][rs]=res;
return res;
}
int gf(int u)
{
if(u==fa[u]) return u;
fa[u]=gf(fa[u]);
return fa[u];
}
int main()
{
register ll i,j,k,p,q;
memset(first,-1,sizeof(first));
memset(dp,-1,sizeof(dp));
cin>>n;
for(i=1; i<=n; i++) fa[i]=i;
for(i=1; i<=n; i++)
{
scanf("%lld%lld",&p,&q);
zl[i]=p;
add(i,q);
add(q,i);
fa[gf(i)]=gf(q);
}
for(i=1; i<=n; i++)
{
jh[gf(i)].push_back(i);
}
for(i=1; i<=n; i++)
{
if(!jh[i].size()) continue;
find(jh[i][0],-1);
p=first[s];
for(; p!=-1; p=bn[p].next)
{
if(bn[p].to==t)
{
j1=p;
break;
}
}
p=first[t];
for(; p!=-1; p=bn[p].next)
{
if(bn[p].to==s)
{
j2=p;
break;
}
}
an=dfs(s,0,-1);
for(j=0; j<jh[i].size(); j++)
{
dp[jh[i][j]][0]=dp[jh[i][j]][1]=-1;
}
ans+=max(an,dfs(t,0,-1));
get=s=t=j1=j2=0;
}
cout<<ans;
return 0;
}