[ZJOI2008]骑士 基环树

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目传送门

依据题意:我们可以知道这是一道环套树的题  (看了题解后)   QAQ

先来介绍一下什么是基环树(环套树)。

基环树:一棵树上只有一个环,比正常的树多一条边,也就是n个点n条边

如图:

普通树

 基环树(环套树):

既然是基环树(又称环套树)的话,自然就先要找环

找环如下:

 1 void dfs(int x,int fa){
 2     vis[x]=true;//x已经找过 
 3     for(int i=head[x];i!=-1;i=nxt[i]){
 4         int y=ver[i];
 5         if(y==fa)continue;
 6         if(!vis[y]){//若y没有找过,证明没有出现环 
 7             dfs(y,x);
 8         }
 9         else{//若y被找过,则一定有环 
10             id=i;//左右节点连的边
11             r1=x;//环的左节点 
12             r2=y;//环的有节点 
13         }
14     }
15 }

我们又能联想到treedp当然也是看了题解)那到  没有上司的舞会  ,treedp是去还之后才能做的

解释一下下面这句:

id为环的边,因为建的时双向变,所以id^1就是另一条。例如id为x→y 然后id^1为y→x,因为异或为不进位加法,所以保证一奇一偶为连续的,一定为双向变。

1 if(i==id||i==(id^1))continue;

treedp如下:

 1 void treedp(int x,int fa){
 2     f[x][0]=0;//若不选当前节点,则值为0 
 3     f[x][1]=val[x];//若选当前节点,则取x的值 
 4     for(int i=head[x];i!=-1;i=nxt[i]){
 5         int y=ver[i];
 6         if(y==fa)continue;
 7         if(i==id||i==(id^1))continue;//当i为环的边时,要去环dp 
 8         treedp(y,x);
 9         f[x][0]+=max(f[y][0],f[y][1]);//当前点不取时,子节点可取可不取 
10         f[x][1]+=f[y][0];//当前点不取时,子节点必须不取(依据题意) 
11     }
12 }

之后我们要以环的两边节点各做一遍treedp来比较max

并且环是不能取的

 1 for(int i=1;i<=n;i++){
 2         if(vis[i])continue;
 3         dfs(i,-1);
 4         treedp(r1,-1);
 5         sum=f[r1][0];
 6         memset(f,0,sizeof(f));
 7         treedp(r2,-1);
 8         sum=max(sum,f[r2][0]);
 9         ans+=sum;
10     }

至此,基本框架就介绍完了。

下面上代码了

code:

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 const int N=1e6+10;
 4 using namespace std;
 5 int n,tot,id,r1,r2;
 6 int val[N],ver[N*2],head[N],nxt[N*2];
 7 long long f[N][2];
 8 bool vis[N];
 9 long long ans,sum;
10 inline int read(){
11     int x=0,f=1;char ch=getchar();
12     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
13     while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
14     return x*f;
15 }
16 inline void write(int x)
17 {
18     if(x<0)x=-x,putchar('-');
19     if(x>9)write(x/10);
20     putchar(x%10+'0');
21 }
22 void add(int x,int y){
23     ++tot;
24     ver[tot]=y;
25     nxt[tot]=head[x];
26     head[x]=tot;
27 }
28 void treedp(int x,int fa){
29     f[x][0]=0;
30     f[x][1]=val[x];
31     for(int i=head[x];i!=-1;i=nxt[i]){
32         int y=ver[i];
33         if(y==fa)continue;
34         if(i==id||i==(id^1))continue;
35         treedp(y,x);
36         f[x][0]+=max(f[y][0],f[y][1]); 
37         f[x][1]+=f[y][0];
38     }
39 }
40 void dfs(int x,int fa){
41     vis[x]=true;
42     for(int i=head[x];i!=-1;i=nxt[i]){
43         int y=ver[i];
44         if(y==fa)continue;
45         if(!vis[y]){
46             dfs(y,x);
47         }
48         else{
49             id=i;
50             r1=x;
51             r2=y;
52         }
53     }
54 }
55 int main()
56 {
57     memset(head,-1,sizeof(head));
58     tot=1;
59     memset(vis,0,sizeof(vis));
60     n=read();
61     for(int i=1,x,y;i<=n;i++){
62         x=read(),y=read();
63         val[i]=x;
64         add(i,y);
65         add(y,i);
66     }
67     for(int i=1;i<=n;i++){
68         if(vis[i])continue;
69         dfs(i,-1);
70         treedp(r1,-1);
71         sum=f[r1][0];
72         memset(f,0,sizeof(f));
73         treedp(r2,-1);
74         sum=max(sum,f[r2][0]);
75         ans+=sum;
76     }
77     printf("%lld
",ans);
78     return 0;
79 }
80  
原文地址:https://www.cnblogs.com/nlyzl/p/11738211.html