BZOJ 2286 [Sdoi2011]消耗战 ——虚树
虚树第一题。
大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP
#include <map> #include <ctime> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define inf 1e17 #define maxn 500005 int n,m,k,a[maxn]; int h[maxn],to[maxn],ne[maxn],w[maxn],en=0; int dep[maxn],st[maxn][21],_log[maxn],in[maxn],out[maxn],tot,ord[maxn]; ll mn[maxn];int sta[maxn],top=0,last[maxn],idx=0; void add(int a,int b,int c) {to[en]=b;ne[en]=h[a];w[en]=c;h[a]=en++;} void dfs(int o,int fa) { in[o]=++tot;ord[tot]=o; for (int i=h[o];i>=0;i=ne[i]) if (to[i]!=fa){ dep[to[i]]=dep[o]+1; mn[to[i]]=min(mn[o],(ll)w[i]); dfs(to[i],o); ord[++tot]=o; } out[o]=tot; } void initst() { F(i,2,maxn-1) _log[i]=_log[i>>1]+1; F(i,1,20) F(j,1,tot-(1<<i)+1) { if (dep[st[j][i-1]]<dep[st[j+(1<<i-1)][i-1]]) st[j][i]=st[j][i-1]; else st[j][i]=st[j+(1<<i-1)][i-1]; } } int lca(int l,int r) { if (l==r) return l; l=in[l],r=in[r]; if (l>r) swap(l,r); int tmp=_log[r-l+1];// printf("tmp is %d\n",tmp); if (dep[st[l][tmp]]<dep[st[r-(1<<tmp)+1][tmp]]) return st[l][tmp]; else return st[r-(1<<tmp)+1][tmp]; } bool cmp(int a,int b) {return in[a]<in[b];} int hd[maxn],tl[maxn],nxt[maxn],ed,se[maxn]; void add_edge(int a,int b) { if (last[a]!=idx) last[a]=idx,hd[a]=-1; tl[ed]=b; nxt[ed]=hd[a]; hd[a]=ed++; } ll dfs2(int o,int fa) { ll ret=0; for (int i=hd[o];i>=0;i=nxt[i]) if (tl[i]!=fa) ret+=dfs2(tl[i],o); if(se[o]==idx) return mn[o]; return min(ret,(ll)mn[o]); } int main() { memset(h,-1,sizeof h); scanf("%d",&n); mn[1]=inf; F(i,1,n-1) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c);add(b,a,c); } dfs(1,0); F(i,1,tot)st[i][0]=ord[i];initst(); scanf("%d",&m); while (m--) { ed=0; idx++; scanf("%d",&k); F(i,1,k) scanf("%d",&a[i]),se[a[i]]=idx; sort(a+1,a+k+1,cmp); sta[top=1]=1; F(i,1,k) { int l=in[sta[top]],r=in[a[i]],x=lca(sta[top],a[i]); while (dep[sta[top]]>dep[x]) { int tmp; if (dep[x]>dep[sta[top-1]]) tmp=x; else tmp=sta[top-1]; add_edge(sta[top],tmp); add_edge(tmp,sta[top]); top--; } if (x!=sta[top]) sta[++top]=x; sta[++top]=a[i]; } while (top>1) add_edge(sta[top],sta[top-1]),add_edge(sta[top-1],sta[top]),top--; printf("%lld\n",dfs2(1,0)); } }