[SDOI2011] 消耗战
题目链接:戳我
虚树(这是模板题????)
反正是用这个学了一下虚树。其实虚树也不是什么高端玩意儿就是保留了树上有效信息剔除了没有用的信息,一般用来辅助解决树上的动态规划问题。
虚树的讲解详情请看这个
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 300010
using namespace std;
int n,m,t,cnt;
int head[MAXN<<1],fa[MAXN],dep[MAXN],dfn[MAXN],low[MAXN],done[MAXN];
int id[MAXN],siz[MAXN],top[MAXN],son[MAXN],p[MAXN],S[MAXN];
long long minn[MAXN];
struct Edge{int nxt,to;long long dis;}edge[MAXN<<1];
inline void add(int from,int to,int dis)
{edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;}
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
inline void dfs1(int x,int f)
{
fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;
int maxx=-1;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==f) continue;
minn[v]=min(minn[x],edge[i].dis);
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>maxx) maxx=siz[v],son[x]=v;
}
}
inline void dfs2(int x,int topf)
{
dfn[x]=++cnt;
top[x]=topf;
if(son[x]) dfs2(son[x],topf);
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
low[x]=cnt;
}
inline int lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y]) return x;
else return y;
}
inline long long solve(int x)
{
if(done[x]) return minn[x];
long long cur_ans=0;
for(int i=head[x];i;i=edge[i].nxt)
cur_ans+=solve(edge[i].to);
return min(cur_ans,minn[x]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
freopen("ce.out","w",stdout);
#endif
scanf("%d",&n);
memset(minn,0x3f,sizeof(minn));
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs1(1,1);dfs2(1,1);
scanf("%d",&m);
memset(head,0,sizeof(head));
for(int i=1;i<=m;i++)
{
int k;
t=0;
scanf("%d",&k);
for(int j=1;j<=k;j++)
{
scanf("%d",&p[j]);
done[p[j]]=1;
}
sort(&p[1],&p[1+k],cmp);
for(int j=k;j>1;j--)
p[++k]=lca(p[j],p[j-1]);
p[++k]=1;
sort(&p[1],&p[1+k],cmp);
k=unique(&p[1],&p[1+k])-p-1;
for(int j=1,top=0;j<=k;j++)
{
while(top&&low[S[top]]<dfn[p[j]]) --top;
add(S[top],p[j],0);
S[++top]=p[j];
}
printf("%lld\n",solve(1));
//memset(done,0,sizeof(done));
//memset(head,0,sizeof(head));
for(int i=1;i<=k;++i)
done[p[i]]=0,head[p[i]]=0;
}
}