1. 程式人生 > >luogu2607/bzoj1040 [ZJOI2008]騎士 (基環樹形dp)

luogu2607/bzoj1040 [ZJOI2008]騎士 (基環樹形dp)

森林 name 就會 long || line printf 出現 lse

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\n",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\n",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\n",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\n",ans); 102 103 return 0; 104 }

luogu2607/bzoj1040 [ZJOI2008]騎士 (基環樹形dp)