虚树

一般用到只跟点数有关,多次查询的题目时就会用到虚树,同时还要支持快速查询点之间的信息

下面是消耗战的例子

神仙的博客

注意,这道题目的例子有点特殊,所以那位神仙的代码并不是一般题目通用的,但是我的代码是通用的

注意,1一定要加入点集中

#include<bits/stdc++.h>
#define vit vector<int>::iterator 
typedef long long ll;
using namespace std;
const int N=2.9e5;
const int Log=20;
const ll inf=1e15+7;
struct edge
{
	int to,nxt,co;
}e[N*2];
int h[N],E=0;
int siz[N],son[N],dfn[N],mp[N],pa[N],dep[N],top[N],tim=0;
ll st[Log+5][N],p2[Log+5],l2[N],tof[N];
int a[N];
int n,m,k;
int s[N],Top=0;
int used[N];
ll f[N];
vector<int> g[N];
void addedge(int u,int v,int w)
{
	E++;
	e[E].to=v,e[E].nxt=h[u],e[E].co=w;
	h[u]=E;
	return;
}
void vaddedg(int u,int v)
{
	g[u].push_back(v);
	return;
}
void dfs1(int u,int fa,ll co)
{
	tof[u]=co;
	dep[u]=dep[fa]+1;
	siz[u]=1;
	pa[u]=fa;
	son[u]=-1;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		int w=e[i].co;
		if(v==fa) continue;
		dfs1(v,u,w);
		siz[u]+=siz[v];
		if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
	}
	return;
}
void dfs2(int u,int fa)
{
	if(!top[u]) top[u]=u;
	tim++;
	dfn[u]=tim;
	mp[tim]=u;
	st[0][tim]=tof[u];
	if(son[u]!=-1) top[son[u]]=top[u],dfs2(son[u],u);
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa||v==son[u]) continue;
		dfs2(v,u);
	}
	return;
}
int LCA(int u,int v)
{
	for(;top[u]!=top[v];)
	{
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=pa[top[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	return u;
}
ll que(int l,int r)
{
	if(l>r) return inf;
	int s=l2[r-l+1];
	return min(st[s][l],st[s][r-p2[s]+1]);
}
ll cal(int u,int to)
{
	ll res=inf;
	for(;dep[top[u]]>dep[to];u=pa[top[u]]) res=min(res,que(dfn[top[u]],dfn[u]));
	res=min(res,que(dfn[to]+1,dfn[u]));
	return res;
}
void Init()
{
	p2[0]=1;
	for(int i=1;i<=Log;i++) p2[i]=p2[i-1]*2;
	l2[0]=-1;
	for(int i=1;i<=n;i++) l2[i]=l2[i/2]+1;
	for(int i=1;i<=Log;i++)
		for(int j=1;j+p2[i]-1<=n;j++)
			st[i][j]=min(st[i-1][j],st[i-1][j+p2[i-1]]);
	return;
}
int cmp(int a,int b)
{
	return dfn[a]<dfn[b];
}
void vins(int x)
{
	if(!Top) return void(s[++Top]=x);
	int lca=LCA(x,s[Top]);
	if(lca==s[Top]) return void(s[++Top]=x);
	while(Top>1&&dfn[s[Top-1]]>=dfn[lca]) vaddedg(s[Top-1],s[Top]),Top--;
	if(lca!=s[Top]) vaddedg(lca,s[Top]),s[Top]=lca;
	s[++Top]=x;
	return;
}
void DP(int u,ll co)
{
	f[u]=0;
	for(vit it=g[u].begin();it!=g[u].end();it++)
	{
		int v=*it;
		int w=cal(v,u);
		DP(v,w);
		f[u]+=f[v];
	}
	if(used[u]) f[u]=co;
	else f[u]=min(f[u],co);
	g[u].clear();
	return;
}
void build(int k)
{
	for(int i=1;i<=k;i++) scanf("%d",&a[i]);
	sort(a+1,a+k+1,cmp);
	s[Top=1]=1;
	for(int i=1;i<=k;i++)
	{
		vins(a[i]);
		used[a[i]]=1;
	}	
	while(Top>1) vaddedg(s[Top-1],s[Top]),Top--;
	DP(1,inf); 
	for(int i=1;i<=k;i++) used[a[i]]=0;
	return;
}
int main()
{
	scanf("%d",&n);
	int u,v,w;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		addedge(u,v,w);
		addedge(v,u,w);
	}
	dep[0]=-1;
	dfs1(1,0,inf);
	dfs2(1,0);
	Init();
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&k);
		build(k);
		printf("%lld\n",f[1]);
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/SegmentTree/p/12981755.html