BZOJ[1040] [ZJOI2008]骑士
这个题比起暑假集训杀人游戏wq讲的方法来,简化了100倍
首先可以发现,每个人都只恨一个人,如果由此人向他恨的人连边的话,显然每个人之后1个出边,但是会有多个入边,然后其实一条边的作用就是两个端点不能同时出现,那么这个边的方向是无所谓的,所以把所有的边反向,那么这个图就像一棵树了,但还是会有环的情况出现,但是环只会在每一颗树的树根出现(每个人只恨一个人),所以Tarjan缩点,先把树上的贡献集中到环上的根上(树DP),然后再在换上跑一个线性DP就行了
Code
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 # define maxn 1000010 8 typedef long long LL; 9 using namespace std; 10 struct node{ 11 int u,v,nxt; 12 }g[maxn]; 13 int adj[maxn],e; 14 void add(int u,int v){ 15 g[e]=(node){u,v,adj[u]}; 16 adj[u]=e++; 17 } 18 int n,w[maxn]; 19 void init(){ 20 scanf("%d",&n); 21 int x; 22 memset(adj,-1,sizeof(adj)); 23 for(int i=1;i<=n;i++){ 24 scanf("%d%d",&w[i],&x); 25 add(x,i); 26 } 27 } 28 int dfn[maxn],low[maxn],belong[maxn],sum[maxn],stack[maxn],stp,cnt,head; 29 bool instack[maxn]; 30 void tarjan(int x){ 31 dfn[x]=low[x]=++stp; stack[++head]=x; instack[x]=1; 32 for(int i=adj[x];i!=-1;i=g[i].nxt){ 33 int v=g[i].v; 34 if(dfn[v]==-1) tarjan(v),low[x]=min(low[x],low[v]); 35 else if(instack[v]) low[x]=min(low[x],dfn[v]); 36 } 37 if(low[x]==dfn[x]){ 38 int tmp,tim=0; cnt++; 39 while(1){ 40 tmp=stack[head--]; 41 instack[tmp]=0; 42 belong[tmp]=cnt; 43 tim++; 44 if(x==tmp) break; 45 } 46 sum[cnt]=tim; 47 } 48 } 49 LL f1[maxn][2]; 50 void dp1(int x,int id){ 51 // cout<<"x== "<<x<<endl; 52 f1[x][1]=w[x]; 53 for(int i=adj[x];i!=-1;i=g[i].nxt){ 54 int v=g[i].v; if(belong[v]==id) continue; 55 dp1(v,id); 56 f1[x][0]+=max(f1[v][0],f1[v][1]); 57 f1[x][1]+=f1[v][0]; 58 } 59 } 60 LL ans; 61 LL f2[maxn][2][2]; 62 bool vis[maxn]; 63 void dp2(int x,int id){ 64 f2[x][1][1]=f1[x][1]; 65 f2[x][0][0]=f1[x][0]; 66 // cout<<"x== "<<x<<endl; 67 int v; int t=x; 68 for(int i=1;i<sum[id];i++){ 69 for(int j=adj[t];j!=-1;j=g[j].nxt){ 70 v=g[j].v; if(belong[v]==id) break; 71 } 72 f2[v][1][0]=f2[v][1][1]=f1[v][1]; 73 f2[v][0][0]=f2[v][0][1]=f1[v][0]; 74 /* 75 cout<<"v== "<<v<<" "<<f1[v][1]<<endl; 76 if(v==2){ 77 cout<<"check::"<<f2[v][1][0]<<" "<<f2[v][0][1]<<" "<<f2[v][0][0]<<endl; 78 } 79 */ 80 f2[v][1][0]+=f2[t][0][0]; 81 f2[v][1][1]+=f2[t][0][1]; 82 f2[v][0][0]+=max(f2[t][0][0],f2[t][1][0]); 83 f2[v][0][1]+=max(f2[t][0][1],f2[t][1][1]); 84 t=v; 85 } 86 LL mx=0; 87 mx=max(f2[v][1][0],f2[v][0][1]); 88 mx=max(mx,f2[v][0][0]); 89 // cout<<f2[v][1][0]<<" "<<f2[v][0][1]<<" "<<f2[v][0][0]<<endl; 90 ans+=mx; 91 } 92 void work(){ 93 // exit(0); 94 memset(dfn,-1,sizeof(dfn)); 95 for(int i=1;i<=n;i++){ 96 if(dfn[i]==-1) tarjan(i); 97 } 98 for(int i=1;i<=n;i++){ 99 f1[i][0]=0; f1[i][1]=w[i]; 100 if(sum[belong[i]]>1){ 101 dp1(i,belong[i]); 102 } 103 } 104 /* 105 for(int i=1;i<=n;i++){ 106 cout<<"i== "<<i<<" "<<f1[i][0]<<" "<<f1[i][1]<<endl; 107 } 108 */ 109 for(int i=1;i<=n;i++){ 110 if(!vis[belong[i]] && sum[belong[i]]>1){ 111 vis[belong[i]]=1; 112 dp2(i,belong[i]); 113 } 114 } 115 cout<<ans<<endl; 116 } 117 int main(){ 118 //freopen("a.in","r",stdin); 119 init(); 120 work(); 121 }