首页 > 代码库 > luogu P2495 [SDOI2011]消耗战

luogu P2495 [SDOI2011]消耗战

二次联通门 : luogu P2495 [SDOI2011]消耗战

 

 

 

 

/*
    luogu P2495 [SDOI2011]消耗战

    虚树+树形dp

    首先对原图构建出虚树

    在建图的时候处理出最小值
    转移即可

    小技巧
    在dp的过程中可以顺便把边表清空
    将边结构体封装可方便的建多张图
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

#define INF 1e17

inline void read (int &now)
{
    register char c = getchar ();
    for (now = 0; !isdigit (c); c = getchar ());
    for (; isdigit (c); now = now * 10 + c - 0, c = getchar ());
}
#define Max 1000010

struct Edge
{
    int to, next, w; 
    Edge (int _x, int _y, int _z) : to (_x), next (_y), w (_z) {}
    Edge () {}
};

int N, M;
long long value[Max];
int dfn[Max], Count;
struct Graph
{
    Edge e[Max << 1];
    int C;
    Graph () { C = 0;}

    int list[Max];
    inline void Clear ()
    {
        C = 0;
    }
    inline void Add_Edge (int from, int to, int dis)
    {
        if (from == to) return ;
        e[++ C].to = to;
        e[C].next = list[from];
        list[from] = C;
        e[C].w = dis; 
    }
    inline void Add_Edge (int from, int to)
    {
        if (from == to) return ;
        e[++ C].to = to;
        e[C].next = list[from];
        list[from] = C;
    }
};

inline void swap (int &x, int &y)
{
    int now = x;
    x = y;
    y = now;
}

inline long long min (int x, long long y)
{
    return x < y ? x : y;
}

class Tree_Chain_Get
{
    private : 
        Graph G;
        int  size[Max], chain[Max], father[Max], son[Max];

    public :

        int deep[Max];

        void Dfs_1 (int now, int Father)
        {
            size[now] = 1;
            dfn[now] = ++ Count;
            for (int i = G.list[now]; i; i = G.e[i].next)
                if (G.e[i].to != Father)
                {
                    Dfs_1 (G.e[i].to, now);
                    father[now] = Father;
                    size[now] += size[G.e[i].to];
                    deep[now] = deep[Father] + 1;
                    value[G.e[i].to] = min (G.e[i].w, value[now]); 
                    if (size[son[now]] < size[G.e[i].to])
                       son[now] = G.e[i].to; 
                }
        }       
        
        void Dfs_2 (int now, int point)
        {
           chain[now] = point;
           if (son[now])
              Dfs_2 (son[now], point);
           else return ;
           for (int i = G.list[now]; i; i = G.e[i].next)
              if (G.e[i].to != son[now] && G.e[i].to != father[now])
                 Dfs_2 (G.e[i].to, G.e[i].to);
        }
        
        int Get_Lca (int x, int y)
        {
            for (; chain[x] != chain[y]; )
            {
                if (deep[chain[x]] < deep[chain[y]])
                    swap (x, y);
                x = father[chain[x]];
            }
            return deep[x] < deep[y] ? x : y;
        }
        
        inline void Insert_edges (const int L)
        {
            for (int i = 1, x, y, z; i <= L; ++ i)
            {
                read (x), read (y), read (z);
                G.Add_Edge (x, y, z);
                G.Add_Edge (y, x, z);
            }
            value[1] = INF;
            deep[1] = 0;
            Dfs_1 (1, 0);
            Dfs_2 (1, 1);
        }
};
Tree_Chain_Get Lca;

inline bool Comp (const int &x, const int &y)
{
    return dfn[x] < dfn[y];
}

class Virtual_Tree
{
    private : Graph T; int Stack[Max], top;
            long long dp[Max];
            int queue[Max];

    public :

        Virtual_Tree () {top = 0;}

        void Build_Tree ()
        {
            int M;
            read (M);
            for (int i = 1; i <= M; ++ i)
                read (queue[i]);
            std :: sort (queue + 1, queue + 1 + M, Comp);
            int cur = 0;
            for (int i = 2; i <= M; ++ i)
                if (Lca.Get_Lca (queue[i], queue[cur]) != queue[cur])
                    queue[++ cur] = queue[i];
            int top = 0;
            Stack[++ top] = 1;
            int __lca;
            T.Clear ();
            for (int i = 1; i <= cur; ++ i)
            {
                __lca = Lca.Get_Lca (Stack[top], queue[i]);
                for (; ; )
                {
                    if (Lca.deep[Stack[top - 1]] <= Lca.deep[__lca])
                    {
                        T.Add_Edge (__lca, Stack[top]);
                        -- top;
                        if (Stack[top] != __lca)
                            Stack[++ top] = __lca;
                        break;
                    }
                    T.Add_Edge (Stack[top - 1], Stack[top]);
                    -- top;
                }
                if (Stack[top] != queue[i])
                    Stack[++ top] = queue[i];
            }
            top --;
            for (; top; -- top)
                T.Add_Edge (Stack[top], Stack[top + 1]);
            Dp (1);
            printf ("%lld\n", dp[1]);
        }
               

        void Dp (int now)
        {
            long long res = 0; dp[now] = value[now];
            for (int i = T.list[now]; i; i = T.e[i].next)
            {
                Dp (T.e[i].to);
                res += dp[T.e[i].to];
            }
            T.list[now] = 0;
            if (!res)
                dp[now] = value[now];
            else if (res < dp[now])
                dp[now] = res;
        }

        void Doing (const int &K)
        {
            for (int i = 1; i <= K; ++ i)
                Build_Tree ();
        }
};

Virtual_Tree V_T;

int main (int argc, char *argv[])
{
    read (N);

    Lca.Insert_edges (N - 1);
    int K;
    read (K);
    V_T.Doing (K);

    return 0;
}

 

luogu P2495 [SDOI2011]消耗战