luoguP2495 [SDOI2011]消耗战

题意

首先先把虚树建出来。

\(f[i]\)表示将\(i\)的子树割断的最小代价,\(minn[i]\)表示从\(1\)\(i\)的路径上最小的边,那么有:
\(f[x]=minn[x]\)
如果x不是资源点:
\(f[x]=min(f[x],\sum\limits_{y\in\ somn_x}f[y]\)

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=250010;
int n,m,cnt,top,t,tim;
int head[maxn],a[maxn],sta[maxn],dep[maxn],f[maxn],dfn[maxn],minn[maxn];
int anc[maxn][25];
bool check[maxn];
struct node{int to,dis;};
vector<node>V[maxn];
struct edge{int to,nxt;}e[maxn<<1];
inline int read()
{
	char c=getchar();int res=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
	return res*f;
}
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
inline void add(int u,int v)
{
	e[++cnt].nxt=head[u];
	head[u]=cnt;
	e[cnt].to=v;
}
void dfs_pre(int x,int fa)
{
	dep[x]=dep[fa]+1;dfn[x]=++tim;
	for(int i=1;i<=t;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
	for(unsigned int i=0;i<V[x].size();i++)
	{
		int y=V[x][i].to;
		if(y==fa)continue;
		anc[y][0]=x;minn[y]=min(minn[x],V[x][i].dis);
		dfs_pre(y,x);
	}
}
inline int lca(int x,int y)
{
	if(dep[x]>dep[y])swap(x,y);
	for(int i=t;~i;i--)if(dep[anc[y][i]]>=dep[x])y=anc[y][i];
	if(x==y)return x;
	for(int i=t;~i;i--)if(anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
	return anc[x][0];
}
inline void build(int k,int *a)
{
	cnt=0;
	sort(a+1,a+k+1,cmp);
	sta[top=1]=1;head[1]=0;
	for(int i=1;i<=k;i++)
	{
		if(a[i]==1)continue;
		int x=lca(sta[top],a[i]);
		if(sta[top]!=x)
		{
			while(top>1&&dfn[sta[top-1]]>dfn[x])add(sta[top-1],sta[top]),top--;
			if(dfn[sta[top-1]]!=dfn[x])head[x]=0,add(x,sta[top]),sta[top]=x;
			else add(x,sta[top--]);
		}
		head[a[i]]=0;
		sta[++top]=a[i];
	}
	for(int i=1;i<=top-1;i++)add(sta[i],sta[i+1]);
}
void dfs(int x,int fa)
{
	//cerr<<x<<' '<<check[x]<<endl;
	f[x]=minn[x];
	int res=0;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==fa)continue;
		dfs(y,x);res+=f[y];
	}
	if(res&&!check[x])f[x]=min(res,minn[x]);
	check[x]=0;
}
signed main()
{
	n=read();t=log2(n)+1;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read(),w=read();
		V[u].push_back((node){v,w}),V[v].push_back((node){u,w});
	}
	memset(minn,0x3f,sizeof(minn));
	dfs_pre(1,0);
	m=read();
	for(int i=1;i<=m;i++)
	{
		int k=read();
		for(int j=1;j<=k;j++)a[j]=read(),check[a[j]]=1;
		f[1]=0;
		build(k,a);dfs(1,0);
		printf("%lld\n",f[1]);
	}
	return 0;
}
posted @ 2019-12-02 20:25  nofind  阅读(94)  评论(0编辑  收藏  举报