<虚树+树型DP> SDOI2011消耗战

<虚树+树型DP> SDOI2011消耗战

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

typedef long long LL;
const int MAXN = 25e4 + 10;

inline LL in()
{
    LL x = 0, flag = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') flag = 1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return x * flag;
}

int n, m;

struct Gra
{
    int head[MAXN], nume;
    struct Adj { int nex, to; LL w; } adj[MAXN << 1] ;
    void clear()
        {
            memset(head, 0, sizeof head);
            nume = 0;
        }
    void addedge(int from, int to, LL w)
        {
            adj[++ nume] = (Adj) { head[from], to, w } ;
            head[from] = nume ;
        }
    void link(int from, int to, LL w)
        {
            addedge(from, to, w);
            addedge(to, from, w);
        }
} g[2];
int dep[MAXN], up[21][MAXN], lg[MAXN], dfn[MAXN], ind;
LL mn[MAXN];
void DFS(int u, int fa)
{
    dfn[u] = ++ ind;
    dep[u] = dep[fa] + 1;
    up[0][u] = fa;
    for (int i = 1; (1 << i) <= dep[u]; ++ i)
        up[i][u] = up[i - 1][up[i - 1][u]];
    for (int i = g[0].head[u]; i; i = g[0].adj[i].nex)
    {
        int v = g[0].adj[i].to;
        if (v == fa) continue;
        mn[v] = min(mn[u], g[0].adj[i].w);
        DFS(v, u);
    }
}
int lca(int x, int y)
{
    if (dep[x] > dep[y]) swap(x, y);
    while (dep[x] != dep[y]) y = up[lg[dep[y] - dep[x]]][y];
    if (x == y) return x;
    for (int i = lg[dep[x]]; i >= 0; -- i)
        if (up[i][x] != up[i][y]) x = up[i][x], y = up[i][y];
    return up[0][x];
}

int key[MAXN], stk[MAXN], top;
bool iskey[MAXN];
void insert(int u)
{
    if (top == 1) return  (void) (stk[++ top] = u);
    int LCA = lca(u, stk[top]);
    if (LCA == stk[top]) return (void) (stk[++ top] = u);
    while (top > 1 && dep[LCA] <= dep[stk[top - 1]])
    {
        g[1].addedge(stk[top - 1], stk[top], 0);
        -- top;
    }
    if (LCA != stk[top]) g[1].addedge(LCA, stk[top], 0), stk[top] = LCA;
    stk[++ top] = u;
}
LL search(int u)
{
    LL ret = 0;
    for (int i = g[1].head[u]; i; i = g[1].adj[i].nex)
    {
        int v = g[1].adj[i].to;
        ret += search(v);
    }
    if (iskey[u] || ret > mn[u] * 1LL) ret = mn[u];
    iskey[u] = false; g[1].head[u] = 0;
    return ret;
}

bool cmp(int x, int y) { return dfn[x] < dfn[y]; }

int main()
{
    n = in();
    for (int i = 1; i <= n; ++ i) lg[i] = lg[i - 1] + ((2 << lg[i - 1]) == i);
    for (int i = 1; i < n; ++ i)
    {
        int u = in(), v = in(); LL w = in();
        g[0].link(u, v, w);
    }
    mn[1] = 1e18;
    DFS(1, 0);
    m = in();
    while (m --)
    {
        int q = in();
        for (int i = 1; i <= q; ++ i) key[i] = in(), iskey[key[i]] = true ;
        sort(key + 1, key + q + 1, cmp);
        top = 0;
        stk[++ top] = 1;
        for (int i = 1; i <= q; ++ i) insert(key[i]);
        while (top > 1) g[1].addedge(stk[top - 1], stk[top], 0), -- top;
        g[1].nume = 0;
        printf("%lld\n", search(1));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ikihsiguoyr/p/10805036.html

时间: 2024-11-05 14:41:09

<虚树+树型DP> SDOI2011消耗战的相关文章

[SDOI2011][BZOJ2286] 消耗战|虚树|树型dp|树上倍增LCA

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1040  Solved: 363[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸

bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1276  Solved: 445[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸

【BZOJ2286】[Sdoi2011]消耗战 虚树

[BZOJ2286][Sdoi2011]消耗战 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿.由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小. 侦查部门还发现,敌军有

P2495 [SDOI2011]消耗战 虚树

这是我做的第一道虚树题啊,赶脚不错.其实虚树也没什么奇怪的,就是每棵树给你一些点,让你多次查询,但是我不想每次都O(n),所以我们每次针对给的点建一棵虚树,只包含这些点和lca,然后在这棵虚树上进行树形dp,维护每个点的最小连边权值,这样的复杂度就会降低不少.这里我写了两种写法(其实都是抄的),一种是正常建树的正常做法,还有一种是不用建树,只用堆维护,模拟一棵树的操作,维护欧拉序,就是一个点有进入的编号,也有出去的编号.这样就可以不用真正建出虚树而能进行查询. 题干: 题目描述 在一场战争中,战

HDU1561 The more, The Better(树型DP)

题目是有n个存有宝藏的城堡,攻克任何一个城堡都需要先攻克0个或其他1个城堡,问攻克m个城堡最多能得到多少宝藏. 题目给的城堡形成一个森林,添加一个超级根把森林连在一起就是树了,那么就考虑用树型DP: dp[u][m]表示以u结点为根的子树攻克m个结点的最大价值 但是这样转移太难了,根是从每个孩子通过各自分配若干的城堡去攻克转移的,一个排列组合数,阶乘,是指数级的时间复杂度! 看了题解,原来这是依赖背包,没看背包九讲..不过网上的博客似乎没说清楚,事实上这个状态应该是三个维度来表示: dp[u][

POJ3659 Cell Phone Network(树上最小支配集:树型DP)

题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. 树上的每个结点作为其子树的根可以有三个状态: 不属于支配集且还没被支配 不属于支配集但被其孩子支配 属于支配集 那么就是用dp[u][1\2\3]来表示动归的状态. 123转移该怎么转移就怎么转移..最后的结果就是min(dp[root][2],dp[root][3]). 要注意的是对于有些结点前2

HDU_1561_The more, The Better_树型dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1561 The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7031    Accepted Submission(s): 4121 Problem Description ACboy很喜欢玩一种战略游戏,

HDU_1520_Anniversary party_树型dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8233    Accepted Submission(s): 3574 Problem Description There is going to b

二叉苹果树(树型DP+背包)

二叉苹果树 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点).这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树: 2   5 \  / 3  4 \  / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 程序名:apple 输入格式: 第1行2个数,N和Q(1<=Q<= N,1<N<=