第一行一个整数n,代表岛屿数量。
接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。
第n+1行,一个整数m,代表敌方机器能使用的次数。
接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。
输出有m行,分别代表每次任务的最小代价。
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
Stage2 day2
虚树+树形DP
每次都建出一棵虚树,虚树上有一点有资源,有些点没资源。于是问题变成一棵树上有黑点和白点,求将所有黑点和根节点断开的最小花费。
树形DP解决。最开始预处理每个点到根的路径的最短边mn[i]。f[i]表示断开i的子树中黑点的最小花费。
如果i是黑点,f[i]=mn[i];
如果i是白点,f[i]=min(mn[i],∑f[j]),其中j是i的儿子。
各种蜜汁错误...调了很长时间...怪自己写模板不熟练
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 250005 #define inf 1000000000000000000ll using namespace std; int n,m,k,cnt,tot,top; int head[maxn],head2[maxn],d[maxn],pos[maxn],p[maxn][25],a[maxn],s[maxn]; bool tag[maxn]; ll f[maxn],mn[maxn]; struct edge_type{int next,to,v;}e[maxn*2]; struct edge_type2{int next,to;}e2[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add_edge(int x,int y,int z) { e[++cnt]=(edge_type){head[x],y,z};head[x]=cnt; e[++cnt]=(edge_type){head[y],x,z};head[y]=cnt; } inline void add_edge2(int x,int y) { e2[++cnt]=(edge_type2){head2[x],y};head2[x]=cnt; } inline bool cmp(int x,int y) { return pos[x]<pos[y]; } inline void dfs(int x,int fa) { pos[x]=++tot; for(int i=1;(1<<i)<=d[x];i++) p[x][i]=p[p[x][i-1]][i-1]; for(int i=head[x];i;i=e[i].next) if (e[i].to!=fa) { mn[e[i].to]=min(mn[x],(ll)e[i].v); d[e[i].to]=d[x]+1; p[e[i].to][0]=x; dfs(e[i].to,x); } } inline int lca(int x,int y) { if (d[x]<d[y]) swap(x,y); int t=d[x]-d[y]; for(int i=0;(1<<i)<=t;i++) if (t&(1<<i)) x=p[x][i]; if (x==y) return x; D(i,20,0) if (p[x][i]!=p[y][i]) x=p[x][i],y=p[y][i]; return p[x][0]; } inline void dp(int x) { f[x]=mn[x]; ll tmp=0; for(int i=head2[x];i;i=e2[i].next) dp(e2[i].to),tmp+=f[e2[i].to]; if (tmp&&!tag[x]) f[x]=min(f[x],tmp); head2[x]=0; } inline void solve() { cnt=0; k=read(); F(i,1,k) a[i]=read(),tag[a[i]]=true; sort(a+1,a+k+1,cmp); top=0; F(i,1,k) { if (top==0){s[++top]=a[i];continue;} int lc=lca(s[top],a[i]); while (d[lc]<d[s[top]]) { if (d[lc]>=d[s[top-1]]) { add_edge2(lc,s[top]); if (s[--top]!=lc) s[++top]=lc; break; } add_edge2(s[top-1],s[top]);top--; } s[++top]=a[i]; } while (top>1) add_edge2(s[top-1],s[top]),top--; dp(s[1]);printf("%lld\n",f[s[1]]); for (int i=1;i<=k;i++) tag[a[i]]=false; } int main() { n=read(); F(i,1,n-1) { int x=read(),y=read(),z=read(); add_edge(x,y,z); } mn[1]=inf;dfs(1,0); m=read(); while (m--) solve(); return 0; }