传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2286
思路:构建虚树,treeDP,
设f[i]表示i的子树所有资源点断开所需代价,dis[i]表示=i到1的路径上的最小边权
那么如果i是有资源的点,f[i]=dis[i]
否则f[i]=min(Σf[son[i]],dis[i])
虚树见上一篇博客:http://http://blog.csdn.net/thy_asdf/article/details/50387136
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define min(a,b) (a<b?a:b) typedef long long ll; const int maxn=250010,maxm=500010,maxk=22; const ll inf=1ll<<50; using namespace std; int n,m,fa[maxn][maxk],dep[maxn],cnt,poi[maxn],stk[maxn],top,dfn[maxn],tim;ll f[maxn],dis[maxn]; bool bo[maxn]; bool cmp(int a,int b){return dfn[a]<dfn[b];} struct Tgraph{ int pre[maxm],now[maxn],son[maxm],val[maxm],tot; void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;} void dfs1(int x){ dfn[x]=++tim; for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0]) dep[son[y]]=dep[x]+1,dis[son[y]]=min(dis[x],val[y]),fa[son[y]][0]=x,dfs1(son[y]); } void dfs2(int x){ f[x]=dis[x];ll sum=0; for (int y=now[x];y;y=pre[y]) dfs2(son[y]),sum+=f[son[y]]; if (sum&&!bo[x]) f[x]=min(f[x],sum); now[x]=0; } }g1,g2; int lca(int a,int b){ if (dep[a]<dep[b]) swap(a,b); for (int h=dep[a]-dep[b],i=20;i>=0;i--) if (h>=(1<<i)) h-=(1<<i),a=fa[a][i]; if (a==b) return a; for (int i=20;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i]; return fa[a][0]; } void work(){ top=0; for (int i=1;i<=cnt;i++){ if (!top){stk[++top]=poi[i];continue;} int u=lca(stk[top],poi[i]); while (dfn[u]<dfn[stk[top]]){ if (dfn[u]>=dfn[stk[top-1]]){ g2.add(u,stk[top]); if (stk[--top]!=u) stk[++top]=u; break; } g2.add(stk[top-1],stk[top]),top--; } stk[++top]=poi[i]; } while (top>1) g2.add(stk[top-1],stk[top]),top--; g2.dfs2(stk[1]),printf("%lld\n",f[stk[1]]); for (int i=1;i<=cnt;i++) bo[poi[i]]=0;g2.tot=0; } int main(){ scanf("%d",&n),dis[1]=inf; for (int i=1,a,b,c;i<n;i++) scanf("%d%d%d",&a,&b,&c),g1.add(a,b,c),g1.add(b,a,c); g1.dfs1(1),scanf("%d",&m); for (int i=1;i<=m;i++){ scanf("%d",&cnt); for (int j=1;j<=cnt;j++) scanf("%d",&poi[j]),bo[poi[j]]=1; sort(poi+1,poi+1+cnt,cmp),work(); } return 0; }