bzoj2286:[SDOI2011]消耗战

传送门

虚树裸题,建完虚树上tree dp就好了
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=2.5e5+10;
int f[maxn][20],nid,dep[maxn],top,st[maxn],n,m,id[maxn],q[maxn];
struct oo{int cnt,pre[maxn*2],nxt[maxn*2],h[maxn],v[maxn*2];}a,b;
long long w[maxn],ans[maxn];
void add(int x,int y,int z)
{
    a.pre[++a.cnt]=y,a.nxt[a.cnt]=a.h[x],a.h[x]=a.cnt,a.v[a.cnt]=z;
    a.pre[++a.cnt]=x,a.nxt[a.cnt]=a.h[y],a.h[y]=a.cnt,a.v[a.cnt]=z;
}
void dfs(int x,int fa)
{
    for(rg int i=1;i<20;i++)
    {
        if((1<<i)>dep[x])break;
        f[x][i]=f[f[x][i-1]][i-1];
    }
    id[x]=++nid;
    for(rg int i=a.h[x];i;i=a.nxt[i])
        if(a.pre[i]!=fa)
        {
            f[a.pre[i]][0]=x,dep[a.pre[i]]=dep[x]+1;
            w[a.pre[i]]=min(w[x],1ll*a.v[i]),dfs(a.pre[i],x);
        }
}
int lca(int x,int y)
{
    if(dep[x]>dep[y])swap(x,y);
    int poor=dep[y]-dep[x];
    for(rg int i=19;i>=0;i--)if(poor&(1<<i))y=f[y][i];
    for(rg int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return x==y?x:f[x][0];
}
bool cmp(int x,int y){return id[x]<id[y];}
void link(int x,int y)
{
    b.pre[++b.cnt]=y,b.nxt[b.cnt]=b.h[x],b.h[x]=b.cnt;
    b.pre[++b.cnt]=x,b.nxt[b.cnt]=b.h[y],b.h[y]=b.cnt;
}
void dp(int x,int fa)
{
    long long now=0;ans[x]=w[x];
    for(rg int i=b.h[x];i;i=b.nxt[i])if(b.pre[i]!=fa)dp(b.pre[i],x),now+=ans[b.pre[i]];
    b.h[x]=0;
    if(now)ans[x]=min(ans[x],now);
//	printf("%d %d %d
",x,ans[x],w[x]);
}
signed main()
{
    read(n);
    for(rg int i=1,x,y,z;i<n;i++)read(x),read(y),read(z),add(x,y,z);
    w[1]=1e17,dfs(1,0),read(m);
    for(rg int x=1,t;x<=m;x++)
    {
        read(t),b.cnt=top=0;
        for(rg int i=1;i<=t;i++)read(q[i]);
        sort(q+1,q+t+1,cmp);st[++top]=1;int tot=1;
        for(rg int i=2;i<=t;i++)if(lca(q[i],q[tot])!=q[tot])q[++tot]=q[i];
        for(rg int i=1;i<=tot;i++)
        {
            int w=0,e=0;
            while(top&&lca(st[top],q[i])!=st[top])
            {
                if(w)link(w,st[top]);
                w=st[top],top--;
            }
            if(w)e=lca(w,q[i]),link(w,e);
            if(e&&e!=st[top])st[++top]=e;
            st[++top]=q[i];
        }
        while(top>1)link(st[top],st[top-1]),top--;
        dp(1,0);
        printf("%lld
",ans[1]);
    }
}