基环树dp入门

我们整个dp的思路就是 先找环 然后进行树形dp 把它看成某种意义的“缩点” 然后进行一个环上的dp

ZJOI 2008, 骑士

 #include <bits/stdc++.h>
using namespace  std;
#define  int long long
//typedef long long ll;
typedef pair<int,int> pii;
#define x first
#define y second
#define pb  push_back
#define inf 1e18
#define IOS   std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define  fer(i,a,b)  for(int i=a;i<=b;i++)
#define  der(i,a,b)  for(int i=a;i>=b;i--)
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
const int maxn=1e5+10;
const int mod=1e9+7;
int qmi(int a,int b)
{int res=1;  while(b){  if(b&1) res=res*a%mod;  a=a*a%mod;  b>>=1; } return res;}
const int N=2e5+10;
int dr[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int n,k;
int a[N];
int vis[N];
vector<int>g[N];
int fa[N];
int onc[N];
int dp[N][2];
int ans;
int dp2[N][2];
void dfs(int u)
{
   vis[u]=true;
   dp[u][1]=a[u];
   for(auto v:g[u])
   {
       if(onc[v])continue;
       dfs(v);
       dp[u][0]+=max(dp[v][0],dp[v][1]);
       dp[u][1]+=dp[v][0];
   }
}
void solve()
{
	cin>>n;
	fer(i,1,n)
	{
	    cin>>a[i]>>fa[i];
	    g[fa[i]].pb(i);
	}
	fer(i,1,n)if(!vis[i])
	{
	    int u=i;
	    while(!vis[u])
        {
            vis[u]=true;
            u=fa[u];
        }
        int v=u;
        vector<int>c;
        while(true)
        {
            c.pb(v);
            onc[v]=true;
            v=fa[v];
            if(v==u)break;
        }

	for(auto v:c)dfs(v);
	int m=c.size();
	int ans2=-inf;
    fer(t,0,1)
    {
        fer(j,0,1)
        {
            if(j==t)dp2[0][j]=dp[c[0]][j];
            else dp2[0][j]=-inf;
        }
        fer(i,1,m-1)
        {
            int u=c[i];
            dp2[i][0]=max(dp2[i-1][0],dp2[i-1][1])+dp[u][0];
            dp2[i][1]=dp2[i-1][0]+dp[u][1];
        }
        if(!t)ans2=max(ans2,max(dp2[m-1][0],dp2[m-1][1]));
        else ans2=max(ans2,dp2[m-1][0]);
    }
    ans+=ans2;
	}
	cout<<ans<<endl;
}

signed main()
{
	IOS;
	int _=1;
	//cin>>_;
	while(_--) solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值