[SDOI2011]消耗战(虚树)

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/82178085

虚树就是由树中的几个点及他们的LCA构成的简化的树,因为树的点数被减小,复杂度也随着降低。
首先易证n个点的不同LCA最多只有n-1个,虚树的复杂度就有了保障。
然后我们考虑按照dfs序一个一个点的加入,并用栈维护当前虚树的右链,那么新加入的点x和之前虚树的LCA就是右链最下端的点与x的lca。
然后再维护右链就行。
虚树难在清零和处理非虚树节点的贡献。。。。。。
AC Code:

#include<bits/stdc++.h>
#define maxn 250005
#define LL long long
#define lim 18
using namespace std;

int n;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
int del[maxn],cdel;
inline void Node(int u,int v)
{
    if(!info[u]) del[cdel++] = u;
    Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v;
}
vector<int>G[maxn],W[maxn];
int esiz[maxn];

int Min[lim][maxn],f[lim][maxn],dep[maxn],idx[maxn],tot;
int c[maxn],Q[maxn],tp;
bool is[maxn];

void dfs(int now,int ff)
{
    dep[now] = dep[f[0][now] = ff] + 1;
    idx[now] = ++ tot;
    for(int i=0;i<esiz[now];i++)
        if(G[now][i]!=ff)
        {
            dfs(G[now][i],now);
            Min[0][G[now][i]] = W[now][i];
        }
}

inline bool cmp(const int &a,const int &b){ return idx[a] < idx[b]; }

inline int Lca(int u,int v)
{
    if(dep[u] < dep[v]) swap(u,v);
    for(int i=0;dep[u] > dep[v];i++) if((1<<i) & (dep[u] - dep[v])) u = f[i][u];
    if(u==v) return u;
    for(int i=lim-1;i>=0;i--) if(f[i][u] != f[i][v]) u = f[i][u] , v = f[i][v];
    return f[0][u];
}

inline int cal(int u,int v)
{
    if(dep[u] < dep[v]) swap(u,v);
    int ret = 0x7f7f7f7f;
    for(int i=0;dep[u]-dep[v];i++)
        if((1<<i) & (dep[u] - dep[v]))
            ret = min(ret , Min[i][u]) , u = f[i][u];
    return ret;
}
LL dp[maxn];

void ser(int now)
{
    dp[now] = 0;
    for(int i=info[now];i;i=Prev[i])
    {
        ser(to[i]);
        if(is[to[i]]) dp[now]+=cal(now,to[i]);
        else dp[now]+=min(1ll*cal(now,to[i]) , dp[to[i]]);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1,u,v,w;i<n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        G[u].push_back(v) , G[v].push_back(u);
        W[u].push_back(w) , W[v].push_back(w);
        esiz[u]++,esiz[v]++;
    }

    dfs(1,0);
    for(int j=1;j<lim;j++)
        for(int i=1;i<=n;i++)
            f[j][i] = f[j-1][f[j-1][i]] , Min[j][i] = min(Min[j-1][i] , Min[j-1][f[j-1][i]]);

    int m,k;
    scanf("%d",&m);
    for(;m--;)
    {
        scanf("%d",&k);
        cnt_e = 0;
        for(;cdel;) info[del[--cdel]] = 0;
        for(int i=1;i<=k;i++) scanf("%d",&c[i]) , is[c[i]]=1;
        c[++k] = 1;
        sort(c+1,c+1+k,cmp);
        tp = 0;
        Q[tp++] = c[1];
        for(int i=2;i<=k;i++)
        {
            int lca = Lca(c[i] , Q[tp-1]);
            for(;tp>1 && dep[Q[tp-2]] > dep[lca];tp--) Node(Q[tp-2] , Q[tp-1]);
            if(dep[Q[tp-1]] > dep[lca]) Node(lca , Q[tp-1]) , tp--;
            if(dep[Q[tp-1]] < dep[lca]) Q[tp++] = lca;
            Q[tp++] = c[i];
        }
        for(;tp>1;tp--) Node(Q[tp-2],Q[tp-1]);
        ser(Q[tp-1]);
        printf("%lld\n",dp[Q[tp-1]]);
        for(int i=1;i<=k;i++) is[c[i]] = 0;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/82178085