[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\n",ans); 78 return 0; 79 } 80