luogu2607/bzoj1040 [ZJOI2008]骑士 (基环树形dp)
Posted ressed
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu2607/bzoj1040 [ZJOI2008]骑士 (基环树形dp)相关的知识,希望对你有一定的参考价值。
N个点,每个点发出一条边,那么这个图的形状一定是一个基环树森林(如果有重边就会出现森林)
那我做f[0][x]和f[1][x]分别表示对于x子树,x这个点选还是不选所带来的最大价值
然后就变成了这好几个环上不能选相邻的点,最大的价值和
我们把这个环从N到1处断开,然后钦定一下1选还是不选,统计一下答案就可以了。
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define ll long long 4 using namespace std; 5 const int maxn=1000010; 6 7 inline ll rd(){ 8 ll x=0;char c=getchar();int neg=1; 9 while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();} 10 while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); 11 return x*neg; 12 } 13 14 int N; 15 int eg[maxn*2][2],egh[maxn],ect; 16 int dep[maxn],fa[maxn]; 17 int root[maxn][2],pct,rh[maxn],rct; 18 int stk[maxn],top[maxn]; 19 ll f[2][maxn]; 20 bool flag[maxn],isroot[maxn],connected[maxn]; 21 22 inline void adeg(int a,int b){ 23 eg[++ect][0]=b;eg[ect][1]=egh[a];egh[a]=ect; 24 } 25 inline void adrot(int a,int b){ 26 root[++rct][0]=b;root[rct][1]=rh[a];rh[a]=rct; 27 } 28 29 void dfs1(int ii,int x){ 30 flag[x]=1; 31 //printf("%d %d %d ",x,fa[x],dep[x]); 32 for(int i=egh[x];i!=-1;i=eg[i][1]){ 33 int b=eg[i][0];if(b==fa[x]) continue; 34 //printf("#%d %d %d %d %d ",x,b,flag[b],i,eg[i][1]); 35 if(flag[b]){ 36 if(connected[ii]) continue; 37 int u=x,v=b,lca,cnt=0; 38 if(dep[u]<dep[v]) swap(u,v); 39 while(dep[u]!=dep[v]) adrot(ii,u),isroot[u]=1,u=fa[u]; 40 while(u!=v){ 41 isroot[u]=isroot[v]=1; 42 adrot(ii,u); 43 stk[++cnt]=v; 44 u=fa[u];v=fa[v]; 45 }lca=u;isroot[lca]=1;adrot(ii,lca); 46 for(int j=cnt;j;j--) adrot(ii,stk[j]); 47 connected[ii]=1; 48 }else{ 49 dep[b]=dep[x]+1;fa[b]=x; 50 dfs1(ii,b); 51 } 52 } 53 } 54 55 void dfs2(int x,int F){ 56 for(int i=egh[x];i!=-1;i=eg[i][1]){ 57 int b=eg[i][0];if(b==F||isroot[b]) continue; 58 dfs2(b,x); 59 f[0][x]+=max(f[0][b],f[1][b]); 60 f[1][x]+=f[0][b]; 61 } 62 } 63 64 inline ll solve(int p){ 65 if(rh[p]==-1) return max(f[0][top[p]],f[1][top[p]]); 66 ll re=0; 67 ll g1=f[1][root[rh[p]][0]],g0=0; 68 for(int i=root[rh[p]][1];i!=-1;i=root[i][1]){ 69 ll xx=max(g0,g1); 70 g1=g0+f[1][root[i][0]]; 71 g0=xx+f[0][root[i][0]]; 72 }re=max(re,g0); 73 74 g1=0,g0=f[0][root[rh[p]][0]]; 75 for(int i=root[rh[p]][1];i!=-1;i=root[i][1]){ 76 ll xx=max(g0,g1); 77 g1=g0+f[1][root[i][0]]; 78 g0=xx+f[0][root[i][0]]; 79 }re=max(re,max(g0,g1)); 80 return re; 81 } 82 83 int main(){ 84 int i,j,k; 85 //freopen("2607.in","r",stdin); 86 N=rd();memset(egh,-1,sizeof(egh)); 87 for(i=1;i<=N;i++){ 88 int a=rd(),b=rd(); 89 f[1][i]=a; 90 adeg(i,b);adeg(b,i); 91 }memset(rh,-1,sizeof(rh)); 92 for(i=1;i<=N;i++){ 93 if(!flag[i]) top[++pct]=i,dfs1(pct,i); 94 } 95 //for(i=1;i<=rct;i++) printf("!%d %d %d ",i,root[i][0],root[i][1]); 96 for(i=1;i<=rct;i++) dfs2(root[i][0],0); 97 ll ans=0; 98 for(i=1;i<=pct;i++){ 99 ans+=solve(i); 100 } 101 printf("%lld ",ans); 102 103 return 0; 104 }
以上是关于luogu2607/bzoj1040 [ZJOI2008]骑士 (基环树形dp)的主要内容,如果未能解决你的问题,请参考以下文章