[bzoj2286][Sdoi2011]消耗战

虚树模板题..
Orz w_yqts

#include 
using namespace std;
#define inf (1LL<<60)
#define ll long long
#define N 666666
ll dp[N],v[N];
int num,to[N],Next[N],head[N],len[N];
int num1,to1[N],Next1[N],head1[N];
int top,fa[250005][20],dis[250005][20],deep[N],dfsid[N],a[N],stk[N];
int n;
bool cmp(int x,int y)
{
    return dfsid[x]inline void add(int x,int y,int t)
{
    ++num;
    to[num]=y;
    Next[num]=head[x];
    head[x]=num;
    len[num]=t;
}
inline void add1(int x,int y)
{
    if (x==y) return;
    //cout<<"xy="<
    ++num1;
    to1[num1]=y;
    Next1[num1]=head1[x];
    head1[x]=num1;
}
void dfsxu(int x,int pre)
{
    if (x==1) deep[x]=1;else deep[x]=deep[pre]+1;
    fa[x][0]=pre;
    dfsid[x]=++top;
    for (int i=head[x];i;i=Next[i])
    if (to[i]!=pre) v[to[i]]=min(v[x],(ll)len[i]),dis[to[i]][0]=len[i],dfsxu(to[i],x);
}
int lca(int x,int y)
{
    if (deep[x]for (int i=19;i>=0;--i) if (deep[fa[x][i]]>=deep[y]) x=fa[x][i];
    if (x==y) return x;
    for (int i=19;i>=0;--i) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
void dfs(int x)
{
    dp[x]=v[x];
    ll res=0LL;
    for (int i=head1[x];i;i=Next1[i])
    dfs(to1[i]),res+=dp[to1[i]];
    if (res) dp[x]=min(dp[x],res);
    head1[x]=0;
}
void solve()
{
    int m;
    scanf("%d",&m);
    for (int i=1;i<=m;++i) scanf("%d",&a[i]);
    sort(a+1,a+1+m,cmp);
    int tot=1;
    for (int i=2;i<=m;++i) if (lca(a[i],a[tot])!=a[tot]) a[++tot]=a[i];
    top=0;
    stk[++top]=1;
    for (int i=1;i<=tot;++i)
    {
        int t=lca(a[i],stk[top]);
        while (1)
        {
            if (deep[t]>=deep[stk[top-1]])
            {
                add1(t,stk[top]);--top;
                if (stk[top]!=t) stk[++top]=t;
                break;
            }
            add1(stk[top-1],stk[top]);--top;
        }
        if (stk[top]!=a[i]) stk[++top]=a[i];
        //cout<<"stk=================="<
        //for (int i=1;i<=top;++i) cout<
    }
    while (top>1) add1(stk[top-1],stk[top]),--top;
    //cout<<"ok="<
    //cout<<"num1="<
    dfs(1);
    //for (int i=1;i<=n;++i) cout<
    printf("%lld\n",dp[1]);
    num1=0;
}
int main()
{
    int Q,x,y,t;
    cin>>n;
    for (int i=1;iscanf("%d%d%d",&x,&y,&t);
        add(x,y,t);add(y,x,t);
    }
    for (int i=1;i<=n;++i) v[i]=inf;
    dfsxu(1,-1);
    for (int i=1;i<20;++i)
    for (int j=1;j<=n;++j)
    fa[j][i]=fa[fa[j][i-1]][i-1],dis[j][i]=min(dis[j][i-1],dis[fa[j][i-1]][i-1]);
    cin>>Q;
    while (Q--) solve();
}

你可能感兴趣的:(虚树)