BZOJ 3037 创世纪

 

 题解:

 首先从基环树上的环上选两个点x,y

 断开x,y之间的边,然后做树形DP.

 设f[x]为选x的情况下的最大值,g[x]为不选x的情况下的最大值.

 分两种情况讨论,

 1.选x,则y一开始就处于被支配状态,在计算y的f[]函数值时需要特判.

 2.不选x,按正常DP做即可.

 

 1 #include<cstdio>
 2 #include<vector>
 3 using namespace std;
 4 #define ll long long
 5 #define FILE "dealing"
 6 #define up(i,j,n) for(int i=j;i<=n;i++)
 7 #define db long double 
 8 #define pii pair<int,int>
 9 #define pb push_back
10 #define mem(a,L) memset(a,0,sizeof(int)*(L+1))
11 template<class T> inline bool cmin(T& a,T b){return a>b?a=b,true:false;}
12 template<class T> inline bool cmax(T& a,T b){return a<b?a=b,true:false;}
13 template<class T> inline T squ(T a){return a*a;}
14 const ll maxn=2000100+10,inf=1e9+10,limit=1e7;
15 int read(){
16     int x=0,f=1,ch=getchar();
17     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
18     while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
19     return x*f;
20 }
21 int n;
22 vector<int> t[maxn];
23 int f[maxn],g[maxn],to[maxn];
24 int vis[maxn];
25 int rt,rt2,q[maxn],top=0;
26 void dfs(int x){
27     q[++top]=x;
28     vis[x]=1;
29     if(!vis[to[x]])dfs(to[x]);
30     else {
31         rt=x;
32         rt2=to[x];
33     }
34 }
35 void dfs2(int x){
36     vis[x]=1;
37     for(int i=0;i<t[x].size();i++)
38         if(!vis[t[x][i]])dfs2(t[x][i]);
39     if(!vis[to[x]])dfs2(to[x]);
40 }
41 //f[x] 选 g[x] 不选
42 int flag=0;
43 void dfs1(int x){//选rt
44     f[x]=1,g[x]=0;int Max=-inf;
45     for(int i=0;i<t[x].size();i++){
46         int y=t[x][i];if((x==rt2&&y==rt))continue;
47         dfs1(y);
48         f[x]+=f[y];
49         g[x]+=f[y];
50         cmax(Max,g[y]-f[y]);
51     }
52     f[x]+=Max;
53     if(x==rt2&&flag)f[x]-=Max;
54     cmax(f[x],0);
55 }
56 
57 int main(){
58     freopen(FILE".in","r",stdin);
59     freopen(FILE".out","w",stdout);
60     n=read();
61     up(i,1,n){
62         to[i]=read();
63         t[to[i]].push_back(i);
64     }
65     int ans=0;
66     up(i,1,n){
67         if(vis[i])continue;
68         top=0;dfs(i);
69         while(top)vis[q[top--]]=0;
70         dfs2(i);
71         int Ans=0;
72         flag=1;
73         dfs1(rt);
74         cmax(Ans,g[rt]);
75         flag=0;
76         dfs1(rt);
77         cmax(Ans,f[rt]);
78         ans+=Ans;
79     }
80     printf("%d\n",ans);
81     return 0;
82 }
View Code

 

转载于:https://www.cnblogs.com/chadinblog/p/6807316.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值