BZOJ 1040 [ZJOI2008]骑士

内向树dp~

就是先找环,任取环上有边相连两点,u和v,以u为根,断开u和v之间的边,做两次树形dp,dp[i][0]表示i不选,dp[i][1]表示i选

①强制u不选,v随意

②u随意,v不选

两种情况取最大值即可~

 

View Code
 1 #include <iostream>

 2 #include <cstring>

 3 #include <cstdio>

 4 #include <cstdlib>

 5 #include <algorithm>

 6 

 7 #define N 2000000

 8 #define M 4000000

 9 

10 using namespace std;

11 

12 int head[N],next[M],to[M],bh[N];

13 int n,ban,rp,cnt,root;

14 long long val[N],ans,res,dp[N][2];

15 bool vis[N],v[N];

16 

17 inline void add(int u,int v)

18 {

19     to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++;

20 }

21 

22 inline void read()

23 {

24     memset(head,-1,sizeof head); cnt=0;

25     scanf("%d",&n);

26     for(int i=1,a;i<=n;i++)

27     {

28         scanf("%lld%d",&val[i],&a);

29         add(i,a); add(a,i);

30     }

31 }

32 

33 inline void circle(int u,int fa)

34 {

35     for(int i=head[u];~i;i=next[i])

36     {

37         if(!bh[to[i]])

38         {

39             bh[to[i]]=true;

40             circle(to[i],u);

41         }

42         else if(to[i]!=fa) rp=u,root=to[i],ban=i;

43     }

44 }

45 

46 inline void dfscir(int u)

47 {

48     dp[u][0]=0; dp[u][1]=val[u];

49     for(int i=head[u];~i;i=next[i])

50         if(i!=ban&&(i^1)!=ban&&!vis[to[i]])

51         {

52             vis[to[i]]=true;

53             dfscir(to[i]);

54             dp[u][1]+=dp[to[i]][0];

55             dp[u][0]=max(dp[to[i]][0],dp[to[i]][1])+dp[u][0];

56         }

57 }

58 

59 inline void dfsban(int u)

60 {

61     dp[u][0]=0; dp[u][1]=val[u];

62     for(int i=head[u];~i;i=next[i])

63         if(i!=ban&&(i^1)!=ban&&!v[to[i]])

64         {

65             v[to[i]]=true;

66             dfsban(to[i]);

67             dp[u][1]+=dp[to[i]][0];

68             if(to[i]==rp) dp[u][0]+=dp[to[i]][0];

69             else dp[u][0]+=max(dp[to[i]][0],dp[to[i]][1]);

70         }

71 }

72 

73 inline void go()

74 {

75     for(int i=1;i<=n;i++)

76         if(!bh[i])

77         {

78             root=-1;bh[i]=true;

79             circle(i,-1);

80             vis[root]=true; dfscir(root); res=dp[root][0];

81             v[root]=true; dfsban(root); res=max(res,max(dp[root][0],dp[root][1]));

82             ans+=res;

83         }

84     printf("%lld\n",ans);

85 }

86 

87 int main()

88 {

89     read();

90     go();

91     return 0;

92 }

 

 

你可能感兴趣的:(2008)