Description
在一场战争中,战场由 $n$ 个岛屿和 $n-1$ 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 $1$ 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 $k$ 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 $1$ 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 $m$ 次,所以我们只需要把每次任务完成即可。
Solution
每次的询问只与某些关键点有关,建出这些关键点的虚树
在虚树上DP即可
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; int n,head[250005],head2[250005],tot,tot2,m,dep[250005],fa[250005][19],lg[250005]={-1},cnt,pos[250005],sta[250005],top,dfn[250005]; long long minn[250005]; bool vst[250005]; struct Edge{ int to,nxt; long long w; }edge[500005],edge2[500005]; inline int read(){ int w=0,f=1; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return w*f; } void dfs1(int k,int f){ dep[k]=dep[f]+1,fa[k][0]=f,dfn[k]=++cnt; for(int i=head[k];i;i=edge[i].nxt){ int v=edge[i].to; if(v!=f)minn[v]=min(minn[k],edge[i].w),dfs1(v,k); } } int LCA(int x,int y){ if(dep[x]<dep[y])swap(x,y); while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]]; if(x==y)return x; for(int i=lg[dep[x]];~i;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } inline bool cmp(int x,int y){return dfn[x]<dfn[y];} inline void addedge(int x,int y){edge2[++tot2]=(Edge){y,head2[x]},head2[x]=tot2;} void build(int K){ sta[top=1]=pos[1],tot2=0; for(int i=2;i<=K;i++){ int lca=LCA(pos[i],sta[top]); while(true) if(dep[lca]>=dep[sta[top-1]]){ if(lca!=sta[top]){ addedge(lca,sta[top]); if(lca!=sta[top-1])sta[top]=lca; else --top; } break; } else addedge(sta[top-1],sta[top]),--top; sta[++top]=pos[i]; } while(--top)addedge(sta[top],sta[top+1]); } long long dfs2(int k){ long long ret=minn[k],s=0; for(int i=head2[k];i;i=edge2[i].nxt)s+=dfs2(edge2[i].to); if(!vst[k])ret=min(ret,s); vst[k]=false,head2[k]=0; return ret; } int main(){ memset(minn,127,sizeof(minn)); for(int i=1;i<=250000;i++)lg[i]=lg[i>>1]+1; n=read(); for(int i=1;i<n;i++){ int u=read(),v=read(),w=read(); edge[++tot]=(Edge){v,head[u],w},head[u]=tot,edge[++tot]=(Edge){u,head[v],w},head[v]=tot; } dfs1(1,0); for(int i=1;i<=18;i++)for(int k=1;k<=n;k++)fa[k][i]=fa[fa[k][i-1]][i-1]; m=read(); for(;m;m--){ int K=read(); for(int i=1;i<=K;i++)pos[i]=read(),vst[pos[i]]=true; sort(pos+1,pos+K+1,cmp),build(K),printf("%lld\n",dfs2(sta[1])); } return 0; }[SDOI2011]消耗战