Educational Codeforces Round 110 (Rated for Div. 2) D. Playoff Tournament

传送门

题意:给你含有2^k-1个节点的满二叉树,对于叶子节点权值:’?‘ = 2, ‘1’ = 1, ‘0’ = 1; 对于非叶子节点 ’?‘ = lsn + rsn, ‘1’ = rsn, ‘0’ = lsn(lsn, rsn分别对应左右节点的权值)。有q次查询,每次把某个节点的字符修改为 ?1 0 中的一个,求修改后根节点的点权。

思路:因为只修改一个点,那么这个点影响的只有它的父亲节点,所以我们把每个节点的点权全部记录下来,然后对于修改后的节点向上递归,一直到根。 边递归边修改。k 最大为18 所以最多向上递归18次。O(18q);

#include<bits/stdc++.h>
using namespace std;

#define lsn (u << 1)
#define rsn (u << 1 | 1)
#define mid (l + r >> 1)

typedef long long ll;
typedef unsigned long long ull;

typedef pair<int, int> P;
typedef pair<double, double> PD;

const int MAXN = (1 << 18) + 10;
const int MAX_LEN = 100000 + 10;
const int MAX_LOG_V = 22;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const ull B = 100000007;

int k;
char s[MAXN], w[MAXN];
int no[MAXN], val[MAXN];

void update(int v) {
    if( (1<<(k-1)) <= v && v <= (1<<k) - 1) {
        if(w[v] == '?') val[v] = 2;
        else val[v] = 1;
    }
    else {
        if(w[v] == '?') val[v] = val[v*2]+val[v*2+1];
        else if(w[v] == '1') val[v] = val[v*2+1];
        else val[v] = val[v*2];
    }
}


//向上更新
void dfs(int v) {
    update(v);
    if(v == 1) return ;
    else dfs(v/2);
}
                                                     
void solve() {
    scanf("%d", &k);
    scanf("%s", s+1);
    int cur = (1<<k) - 1, cnt = 1;
    queue<int> que;
    que.emplace(1);
    //转换为树
    while(cur > 0) {
        for(int i = cur; i < cur + cnt; i++) {
            int v = que.front(); que.pop();
            no[i] = v; 
            w[v] = s[i];
            que.emplace(v*2); que.emplace(v*2 + 1);
        }
        cnt *= 2;
        cur -= cnt;
    }
    for(int i = (1 << k) - 1; i >= 1; i--) {
        update(i);
    }
    int q; scanf("%d", &q);
    while(q--) {
        int p; char op[5];
        scanf("%d %s", &p, op);
        w[no[p]] = *op;
        update(no[p]);
        //如果不为根 就向上更新
        if(no[p] != 1) dfs(no[p]/2); 
        printf("%d\n", val[1]);
    }
}

int main() {
    //ios::sync_with_stdio(false);
    int t = 1; //scanf("%d", &t);
    while(t--) {
        solve();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值