1. 程式人生 > >[BZOJ3572][HNOI2014]世界樹(虛樹DP)

[BZOJ3572][HNOI2014]世界樹(虛樹DP)

iostream ash char ios swa break sort 之前 題目

代碼用時1:15

思想比較簡單的虛樹DP,但細節巨茍,大部分代碼都是LCA/DP/虛樹模板,真正需要自己寫的其實並不多。

寫之前要有一個清晰的思路和框架,細節要有一個比較清楚的認識,不能依賴於別人的代碼。

附上HNOI2014六道題的總結:

T1:類似最小乘積生成樹,KM算法建出凸包即可,套路題。

T2:虛樹DP,想到這個應該就不難了。

T3:語文題。技巧:取log後用加法代替乘法。

T4:字符串hash,模擬題。

T5:復雜度玄學的題目,考場上要敢於寫這種不確定復雜度的題。

T6:SG函數+分塊優化,套路題。

#include<cstdio>
#include<iostream>
#include
<algorithm> #define rep(i,l,r) for (int i=l; i<=r; i++) #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) using namespace std; const int N=300100; int dep[N],p[N],f[N][20],nxt[N],to[N],h[N],bel[N],b[N],rem[N]; int n,x,y,Q,top,m,tim,tot,sz[N],ans[N],qq[N],q[N],stk[N],dfn[N]; template<typename T>inline void
rd(T &x){ int t; char ch; for (t=0; !isdigit(ch=getchar()); t=(ch==-)); for (x=ch-0; isdigit(ch=getchar()); x=x*10+ch-0); if (t) x=-x; } int lca(int a,int b){ if (dep[a]<dep[b]) swap(a,b); int t=dep[a]-dep[b]; for (int i=19; ~i; i--) if (t & (1<<i)) a=f[a][i];
if (a==b) return a; for (int i=19; ~i; i--) if (f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i]; return f[a][0]; } bool cmp(int a,int b){ return dfn[a]<dfn[b]; } int get(int u,int v){ return dep[u]+dep[v]-2*dep[lca(u,v)]; } struct E{ int h[N],to[N<<1],nxt[N<<1],cnt; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int x,int fa){ f[x][0]=fa; dfn[x]=++tim; sz[x]=1; rep(i,1,19) f[x][i]=f[f[x][i-1]][i-1]; For(i,x) if ((k=to[i])!=fa) dep[k]=dep[x]+1,dfs(k,x),sz[x]+=sz[k]; } void dfs2(int x){ qq[++tot]=x; rem[x]=sz[x]; For(i,x) if ((k=to[i])!=f[x][0]){ dfs2(k); if (!bel[k]) continue; int a=get(bel[k],x),b=get(bel[x],x); if (!bel[x] || a<b || (a==b && bel[k]<bel[x])) bel[x]=bel[k]; } } void dfs3(int x){ For(i,x) if ((k=to[i])!=f[x][0]){ int a=get(bel[x],k),b=get(bel[k],k); if (!bel[k]|| a<b || (a==b && bel[x]<bel[k])) bel[k]=bel[x]; dfs3(k); } } void solve(int a,int b){ int x=b,k=b; for (int i=19; ~i; i--) if (dep[f[x][i]]>dep[a]) x=f[x][i]; rem[a]-=sz[x]; if (bel[a]==bel[b]) { ans[bel[a]]+=sz[x]-sz[b]; return; } for (int i=19; ~i; i--){ int t=f[k][i]; if (dep[t]<=dep[a]) continue; int t1=get(bel[a],t),t2=get(bel[b],t); if (t2<t1 || (t1==t2 && bel[b]<bel[a])) k=t; } ans[bel[a]]+=sz[x]-sz[k]; ans[bel[b]]+=sz[k]-sz[b]; } void que(){ rep(i,1,tot) For(p,qq[i]) solve(k=qq[i],to[p]); rep(i,1,tot) ans[bel[qq[i]]]+=rem[qq[i]]; rep(i,1,m) printf("%d ",ans[q[i]]); puts(""); } }G1,G2; void build(){ stk[top=1]=p[1]; rep(i,2,m){ int v=lca(p[i],stk[top]); while (dfn[v]<dfn[stk[top]]){ if (dfn[v]>=dfn[stk[top-1]]){ G2.add(v,stk[top]); if (v!=stk[--top]) stk[++top]=v; break; } G2.add(stk[top-1],stk[top]); top--; } stk[++top]=p[i]; } while (top>1) G2.add(stk[top-1],stk[top]),top--; G2.dfs2(stk[1]); G2.dfs3(stk[1]); rem[stk[1]]=sz[1]; G2.que(); rep(i,1,tot) ans[qq[i]]=G2.h[qq[i]]=rem[qq[i]]=bel[qq[i]]=0; G2.cnt=tot=0; } int main(){ freopen("bzoj3572.in","r",stdin); freopen("bzoj3572.out","w",stdout); rd(n); rep(i,1,n-1) rd(x),rd(y),G1.add(x,y),G1.add(y,x); G1.dfs(1,0); for (rd(Q); Q--; ){ rd(m); rep(i,1,m) scanf("%d",&q[i]),p[i]=q[i],b[q[i]]=1,bel[p[i]]=p[i]; sort(p+1,p+m+1,cmp); build(); } return 0; }

[BZOJ3572][HNOI2014]世界樹(虛樹DP)