[BZOJ4316]小C的独立集(圆方树DP)
题意:求仙人掌图直径。
算法:建出仙人掌圆方树,对于圆点直接做普通的树上DP(忽略方点儿子),方点做环上DP并将值直接赋给父亲。
建图时有一个很好的性质,就是一个方点在邻接表里的点的顺序正好就是从环的根开始的整个环的点的顺序,所以可以直接DP。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=l; i<=r; i++) 4 using namespace std; 5 6 const int N=100010,inf=1000000000; 7 int n,m,tot,tim,top,u,v; 8 int dfn[N],low[N],stk[N],f[N][2],S[N][2]; 9 10 struct E{ 11 int cnt,h[N],nxt[N<<1],to[N<<1]; 12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 13 }G,G1; 14 15 void Tarjan(int x,int pre){ 16 dfn[x]=low[x]=++tim; stk[++top]=x; 17 for (int i=G.h[x],k; i; i=G.nxt[i]) 18 if ((k=G.to[i])!=pre){ 19 if (!dfn[k]){ 20 Tarjan(k,x); low[x]=min(low[x],low[k]); 21 if (low[k]>dfn[x]) top--,G1.add(x,k); 22 else if (low[k]==dfn[x]){ 23 tot++; int t; 24 do{ t=stk[top--]; G1.add(tot,t); } while (t!=k); 25 G1.add(x,tot); G1.add(tot,x); 26 } 27 } 28 else low[x]=min(low[x],dfn[k]); 29 } 30 } 31 32 void dfs(int x,int fa){ printf("%d\n",x); for (int i=G1.h[x],k; i; i=G1.nxt[i]) if (G1.to[i]!=fa) dfs(G1.to[i],x); } 33 34 void DP(int x,int fa){ 35 //printf("%d\n",x); 36 if (x<=n){ 37 f[x][0]=0; f[x][1]=1; 38 for (int i=G1.h[x],k; i; i=G1.nxt[i]){ 39 DP(k=G1.to[i],x); 40 if (k<=n) f[x][0]+=max(f[k][0],f[k][1]),f[x][1]+=f[k][0]; 41 } 42 }else{ 43 for (int i=G1.h[x]; i; i=G1.nxt[i]) if (G1.to[i]!=fa) DP(G1.to[i],x); 44 45 int top=0; 46 for (int i=G1.h[x],k; i; i=G1.nxt[i]) 47 S[++top][0]=f[k=G1.to[i]][0],S[top][1]=f[k][1]; 48 for (int i=top-1; i; i--) 49 S[i][0]+=max(S[i+1][1],S[i+1][0]),S[i][1]+=S[i+1][0]; 50 f[fa][0]=S[1][0]; 51 52 top=0; 53 for (int i=G1.h[x],k; i; i=G1.nxt[i]) 54 S[++top][0]=f[k=G1.to[i]][0],S[top][1]=f[k][1]; 55 S[top][1]=-inf; 56 for (int i=top-1; i; i--) 57 S[i][0]+=max(S[i+1][1],S[i+1][0]),S[i][1]+=S[i+1][0]; 58 f[fa][1]=S[1][1]; 59 } 60 } 61 62 int main(){ 63 freopen("bzoj4316.in","r",stdin); 64 freopen("bzoj4316.out","w",stdout); 65 scanf("%d%d",&n,&m); tot=n; 66 rep(i,1,m) scanf("%d%d",&u,&v),G.add(u,v),G.add(v,u); 67 Tarjan(1,0); DP(1,0); //dfs(1,0); 68 //rep(i,1,tot) printf("%d %d\n",f[i][0],f[i][1]); puts(""); 69 printf("%d\n",max(f[1][0],f[1][1])); 70 return 0; 71 }