HDU 6161 (2017多校9 - STL模拟 + dp)

101 篇文章 1 订阅
18 篇文章 0 订阅

题意:

给你一个n (n <= 1e8)个节点的完全二叉树, 开始时,每个节点的权值 为他本身, 两种操作:

1. 查询经过节点x 的最大权值链。

2. 改变x 的权值为v


思路:

n是1e8,没法建树。

但他是一个完全二叉树,一条链就log n 个点。

那么我们每次修改权值时 , 维护一下这条链的信息。 那么我们只需要n log n 的空间就足够了。


所有 我们令dp[x]表示 从x 往下走 最大权值是多少。

val[x]表示 x 这个点权值是多少,如果没有, 表示为本身(初始状态)

然后就是模拟就行了。


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

map<int, long long >dp, val;
char s[10];
int n, q;
long long calc(int x){
    if (x > n) return 0;
    if (dp.count(x)) return dp[x];

    int d1 = 0;
    int d2 = 0;

    int x2 = x;
    while(x2 <= n){
        ++d1;
        x2 = x2 * 2 + 1;
    }
    int x3 = x;
    while(x3 <= n){
        ++d2;
        x3 = x3 * 2;
    }
    long long sum = 0;
    if (x2 > n){
        x2 >>= 1;
    }

    while(x2 != x){
        sum += x2;
        x2 /= 2;
    }
    sum += x2;
    long long ans = sum;

    sum = 0;

    if (d1 != d2){
        x2 = n;
        while(x2 != x){
            sum += x2;
            x2 /= 2;
        }
        sum += x2;
        ans = max(ans, sum);
    }
    return ans;


}

void change(int x,long long v){
    val[x] = v;
    dp[x] = max(calc(x<<1), calc(x << 1 | 1)) + v;
    int md = x % 2;
    long long ans = max(calc(x<<1) , calc(x << 1 | 1)) + v;
    x/= 2;
    while(x > 1){
        long long t;
        if (val.count(x)) t = val[x];
        else t = x;
//        ans += t;
        if (md){
            dp[x] = max(calc(x << 1), ans) + t;
        }
        else {
            dp[x] = max(ans, calc(x<<1|1) ) + t;
        }
        ans = dp[x];
        md = x % 2;
        x /= 2;
    }
}


long long query(int x){

    long long t;
    if (val.count(x)) t = val[x];
    else t = x;
    long long ans = calc(x << 1) + calc(x << 1 | 1) + t;
    long long tmp = calc(x);
    int md = x % 2;
    x >>= 1;
    while(x >= 1){
        if (val.count(x))t = val[x];
        else t = x;
        tmp += t;
        if (md){
            ans = max(ans, calc(x << 1) + tmp);
        }
        else {
            ans = max(ans, calc(x<<1|1) + tmp);
        }
        md = x % 2;
        x /= 2;
    }
    return ans;
}
int main(){

    while(~scanf("%d %d",&n, &q)){
        val.clear();
        dp.clear();
        for (int i = 0; i < q; ++i){
            scanf("%s", s);
            if (s[0] == 'q'){
                int x;
                scanf("%d",&x);
                long long ans = query(x);
                printf("%I64d\n", ans);
            }
            else {
                int x;
                long long v;
                scanf("%d%I64d", &x, &v);
                change(x, v);
            }
        }
    }
    return 0;
}



Big binary tree

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 492    Accepted Submission(s): 168


Problem Description

You are given a complete binary tree with n nodes. The root node is numbered 1, and node x's father node is  x/2 . At the beginning, node x has a value of exactly x. We define the value of a path as the sum of all nodes it passes(including two ends, or one if the path only has one node). Now there are two kinds of operations:
1.  change u x Set node u's value as x(1≤u≤n;1≤x≤10^10)
2.  query u Query the max value of all paths which passes node u.
 

Input
There are multiple cases.
For each case:
The first line contains two integers n,m(1≤n≤10^8,1≤m≤10^5), which represent the size of the tree and the number of operations, respectively.
Then m lines follows. Each line is an operation with syntax described above.
 

Output
For each query operation, output an integer in one line, indicating the max value of all paths which passes the specific node.
 

Sample Input
  
  
6 13 query 1 query 2 query 3 query 4 query 5 query 6 change 6 1 query 1 query 2 query 3 query 4 query 5 query 6
 

Sample Output
  
  
17 17 17 16 17 17 12 12 12 11 12 12
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:   6181  6180  6179  6178  6177 
 

Statistic |  Submit |  Discuss |  Note

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值