bzoj3252

3252: 攻略

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 469  Solved: 194
[Submit][Status][Discuss]

Description

题目简述:树版[k取方格数]

众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。

今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)

“为什么你还没玩就知道每个场景的价值呢?”

“我已经看到结局了。”

Input

第一行两个正整数n,k

第二行n个正整数,表示每个场景的价值

以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)

保证场景1为根节点

Output

输出一个整数表示答案

Sample Input

5 2

4 3 2 1 1

1 2

1 5

2 3

2 4

Sample Output

10

HINT

对于100%的数据,n<=200000,1<=场景价值<=2^31-1

Source

dfs序+线段树

我太zz了,竟然没想出来。。。

一直觉得一个一个爬上去太慢了,看了题解发现自己是个zz,一共只删n个,也就是说只用爬n次就行了

那么dfs序+线段树 每次给子树全部减这个点的值 然后把这个点的值清0 用线段树维护最大值和位置。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> PII;
const int N = 200010;
struct edge {
    int nxt, to;
} e[N << 1];
int n, k, cnt = 1, tot;
ll ans;
int head[N], dfn[N], low[N], fa[N], mp[N];
ll v[N], w[N], tag[N << 2];
PII tree[N << 2];
void link(int u, int v)
{
    e[++cnt].nxt = head[u];
    head[u] = cnt;
    e[cnt].to = v;
}
namespace seg
{
    void pushdown(int x)
    {
        if(!tag[x]) return;
        tree[x << 1].first += tag[x]; tree[x << 1 | 1].first += tag[x];
        tag[x << 1] += tag[x]; tag[x << 1 | 1] += tag[x];
        tag[x] = 0;
    }
    void build(int l, int r, int x)
    {
        if(l == r) { tree[x].first = w[mp[l]]; tree[x].second = mp[l]; return; }
        int mid = (l + r) >> 1;
        build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1);
        if(tree[x << 1].first > tree[x << 1 | 1].first) tree[x] = tree[x << 1];
        else tree[x] = tree[x << 1 | 1];
    }
    void update(int l, int r, int x, int a, int b, int num)
    {
        if(l > b || r < a) return;
        if(l >= a && r <= b)
        {
            tree[x].first += num; tag[x] += num; return;
        }
        pushdown(x);
        int mid = (l + r) >> 1;
        update(l, mid, x << 1, a, b, num);
        update(mid + 1, r, x << 1 | 1, a, b, num);
        if(tree[x << 1].first > tree[x << 1 | 1].first) tree[x] = tree[x << 1];
        else tree[x] = tree[x << 1 | 1];
    }
} using namespace seg;
void dfs(int u, int last, ll sum)
{
    dfn[u] = ++tot; mp[tot] = u; w[u] = sum;
    for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last)
    {
        fa[e[i].to] = u;
        dfs(e[i].to, u, sum + v[e[i].to]);
    }
    low[u] = tot;
}
void change(int pos)
{
    while(v[pos])
    {
        update(1, n, 1, dfn[pos], low[pos], -v[pos]);
        v[pos] = 0; pos = fa[pos];
    }
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i) scanf("%lld", &v[i]);
    for(int i = 1; i < n; ++i)
    {
        int u, v; scanf("%d%d", &u, &v);
        link(u, v); link(v, u);
    }
    ans = v[1];
    v[1] = 0;
    dfs(1, 0, 0);
    build(1, n, 1);
    while(k--)
    {
        PII x = tree[1];
        ans += x.first;
        change(x.second);
    }
    printf("%lld\n", ans);
    return 0;
}

时间: 2024-11-05 13:47:16

bzoj3252的相关文章

BZOJ3252 攻略

Orz hzwer 只要用堆就可以了,跪烂了... 话说那个什么ext的库真的能用嘛= =,反正我用了烂删除 结果Rank.3←_← 1 /************************************************************** 2 Problem: 3252 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:964 ms 7 Memory:14036 kb 8 *****************

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

线段树 BZOJ3252 攻略

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 496  Solved: 211[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

【Bzoj3252】攻略(dfs序+线段树)

Description 题目链接 Solution 可以想到,每次肯定是拿最大价值为最优 考虑改变树上一个点的值,只会影响它的子树,也就是dfs序上的一个区间, 于是可以以dfs序建线段树,这样就变成区间问题了 Code #include <cstdio> #include <algorithm> #define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1 #define ll long long #defi

BZOJ3252: 攻略 可并堆

网上有很多人说用dfs序+线段树做...其实stl的堆可以...可并堆可以...很多奇奇怪怪的东西都能做... 可并堆比较好想...也比较好写... 分析: 首先,这是一个网络流做不了的题...数据太大... 其次...我们可以这样考虑一下,这个点的子树中,将这个点的权值仅更新给最大的那个就能满足 之后,在每一个叶子节点上,建立一个大根堆,dfs一遍,将子节点的堆合并,之后找到根节点,将根节点的权值加上当前位置的价值 最后,根节点中前k大的权值和即为答案... 附上代码,精简可行 #includ

Dfs【bzoj3252】攻略

Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局.每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的) "为什么你还没玩就知道每个场

[转载]hzwer的bzoj题单

counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ1202 BZOJ1051 BZOJ1001 BZOJ1588 BZOJ1208 BZOJ1491 BZOJ1084 BZOJ1295 BZOJ3109 BZOJ1085 BZOJ1041 BZOJ1087 BZOJ3038 BZOJ1821 BZOJ1076 BZOJ2321 BZOJ1934 BZOJ