代码用时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; }