Bzoj2286--Sdoi2011消耗战
栈模拟dfs,学到了新姿势
这种题很显然应该用虚树去搞,之前也没写过虚树
具体来说就是先维护dfs序,之后每次询问按dfs序排序后一个一个压入栈内,相当于dfs中的进入递归
如果当前压入栈中的元素与之前栈顶元素的Lca深度小于栈顶元素,那么就把栈顶元素弹出,相当于dfs中的返回
虚树上就很好dp了,在模拟dfs时就可以完成dp
代码 :
#include<bits/stdc++.h> #define LL long long #define low(x) (x&(-x)) #define LNF 1000000000000000 using namespace std; inline int _max(int a,int b) {return a>b?a:b;} inline LL _min(LL a,LL b) {return a<b?a:b;} #define MAXN 250005 #define MAXM 500005 int n,m,k,q[MAXN];LL ans; int st[MAXN],top; int head[MAXN],cnt; struct Edge{ int to,next,w; }e[MAXM]; inline void insert(int a,int b,int c) { e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;e[cnt].w=c; e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;e[cnt].w=c; } int dep[MAXN],bz[MAXN][22],mi[MAXN][22],ds[MAXN],ind; void dfs(int v,int fr) { ds[v]=++ind;dep[v]=dep[fr]+1;bz[v][0]=fr; for(int i=head[v];i;i=e[i].next) if(!ds[e[i].to]) { mi[e[i].to][0]=e[i].w; dfs(e[i].to,v); } } inline bool cmp(int a,int b) {return ds[a]<ds[b];} int Lca(int a,int b) { if(dep[a]<dep[b]) swap(a,b); for(int i=20;~i;i--) if(dep[bz[a][i]]>=dep[b]) a=bz[a][i]; for(int i=20;~i;i--) if(bz[a][i]!=bz[b][i]) a=bz[a][i],b=bz[b][i]; return a==b?a:bz[a][0]; } LL dis(int a,int b) { LL ret=LNF; for(int i=20;~i;i--) if(dep[bz[a][i]]>=dep[b]) ret=_min(ret,mi[a][i]),a=bz[a][i]; return ret; } LL dp[MAXN];bool g[MAXN]; void solve() { st[++top]=1; for(int i=1;i<=k;i++) g[q[i]]=1; for(int now,t,i=1;i<=k;i++) { now=q[i];t=Lca(now,st[top]); while(dep[t]<dep[st[top]]) { if(dep[st[top-1]]<=dep[t]) { dp[t]+=_min(g[st[top]]?LNF:dp[st[top]],dis(st[top],t)); g[st[top]]=dp[st[top]]=0;top--; if(st[top]!=t) st[++top]=t; break; } else { dp[st[top-1]]+=_min(g[st[top]]?LNF:dp[st[top]],dis(st[top],st[top-1])); g[st[top]]=dp[st[top]]=0;top--; } } if(st[top]!=now) st[++top]=now; } while(top>1) { dp[st[top-1]]+=_min(g[st[top]]?LNF:dp[st[top]],dis(st[top],st[top-1])); dp[st[top]]=g[st[top]]=0;top--; } printf("%lld\n",dp[top--]);dp[1]=0; } int main() { scanf("%d",&n); for(int a,b,c,i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); insert(a,b,c); } memset(mi,0x3f3f,sizeof(mi)); dfs(1,0); for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) bz[j][i]=bz[bz[j][i-1]][i-1],mi[j][i]=_min(mi[j][i-1],mi[bz[j][i-1]][i-1]); scanf("%d",&m); while(m--) { scanf("%d",&k);ans=0; for(int i=1;i<=k;i++) scanf("%d",&q[i]); sort(q+1,q+k+1,cmp); solve(); } return 0; }