zoukankan      html  css  js  c++  java
  • P3924 康娜的线段树

    P3924 康娜的线段树

    题目描述
    小林是个程序媛,不可避免地康娜对这种人类的“魔法”产生了浓厚的兴趣,于是小林开始教她OI。

    今天康娜学习了一种叫做线段树的神奇魔法,这种魔法可以维护一段区间的信息,是非常厉害的东西。康娜试着写了一棵维护区间和的线段树。由于她不会打标记,因此所有的区间加操作她都是暴力修改的。具体的代码如下:(略)

    显然,这棵线段树每个节点有一个值,为该节点管辖区间的区间和。

    康娜是个爱思考的孩子,于是她突然想到了一个问题:

    如果每次在线段树区间加操作做完后,从根节点开始等概率的选择一个子节点进入,直到进入叶子结点为止,将一路经过的节点权值累加,最后能得到的期望值是多少?

    康娜每次会给你一个值 qwq ,保证你求出的概率乘上 qwq 是一个整数。

    这个问题太简单了,以至于聪明的康娜一下子就秒了。

    现在她想问问你,您会不会做这个题呢?

    (n, m <= 10^{6})

    Solution

    单点将 叶子结点(k) 加上 (x) , 由于线段树的结构, 设此节点处于线段树第 (dep[k]) 层, 有答案加上:

    [x * sum_{i = 0}^{dep[k] - 1}{frac{1}{2^{i}}}$$$$=x * frac{2^{n} - 1}{2^{n - 1}}(n = dep[k]) ]

    然后区间修改可以视为多次单点修改, 互相不构成影响, 令 (a[i] = frac{2^{n} - 1}{2^{n - 1}}) , 固有 (l, r) 的修改总答案加上:

    [x * sum_{i = l}^{r}{a[i]} ]

    可以以前缀和维护 (a[i]) , 故式子变为:

    [(sum[r] - sum[l - 1]) * x ]

    可以在 (O(1)) 的时间内完成一次询问
    现在只需要求解每个叶子节点的深度即可

    处理数据的时候有可能在前缀和部分无法很好的解决精度问题, 为了简便运算, 令所有的 (a[i] *= 2^{maxdep}) , 这样每个 (a[i]) 就变成了

    [(2^{n} - 1) * (2^{maxdep - n + 1}) ]

    在输出的时候统一再除以 (frac = 2^{maxdep}) 即可
    输出为:$$(sum[r] - sum[l - 1]) * x / frac * qwq$$

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    #define LL long long
    #define REP(i, x, y) for(LL i = (x);i <= (y);i++)
    using namespace std;
    LL RD(){
        LL out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const LL maxn = 2000019;
    LL num, na, qwq;
    LL v[maxn], dep[maxn], maxdep;
    LL ans;
    #define lid (id << 1)
    #define rid (id << 1) | 1
    struct seg_tree{
    	LL l, r;
    	LL sum;
    	}tree[maxn << 2];
    void build(LL id, LL l, LL r, LL d){
    	tree[id].l = l, tree[id].r = r;
    	if(l == r){
    		tree[id].sum = v[l];
    		dep[l] = d;
    		maxdep = max(maxdep, d);
    		return ;
    		}
    	LL mid = (l + r) >> 1;
    	build(lid, l, mid, d + 1), build(rid, mid + 1, r, d + 1);
    	tree[id].sum = tree[lid].sum + tree[rid].sum;
    	}
    void dfs(LL id, LL d){
    	ans += tree[id].sum * (1 << (maxdep - d + 1));
    	if(tree[id].l == tree[id].r)return ;
    	dfs(lid, d + 1), dfs(rid, d + 1);
    	}
    LL gcd(LL a, LL b){return !b ? a : gcd(b, a % b);}
    LL a[maxn], sum[maxn];
    int main(){
    	num = RD(), na = RD(), qwq = RD();
    	REP(i, 1, num)v[i] = RD();
    	build(1, 1, num, 1), dfs(1, 1);
    	LL frac = 1 << maxdep;
    	LL d = gcd(frac, qwq);
    	frac /= d, qwq /= d;
    	REP(i, 1, num){
    		a[i] = ((1 << dep[i]) - 1) * (1 << (maxdep - dep[i] + 1));
    		sum[i] = sum[i - 1] + a[i];
    		}
    	while(na--){
    		LL l = RD(), r = RD(), x = RD();
    		ans += (sum[r] - sum[l - 1]) * x;
    		printf("%lld
    ", ans / frac * qwq);
    		}
    	return 0;
    	}
    
  • 相关阅读:
    linux内核中听过就能记住的概念
    专治不会看源码的毛病--spring源码解析AOP篇
    接口性能优化方案及其理论依据
    Redis各种数据结构性能数据对比和性能优化实践
    iOS 防止UIButton重复点击
    iOS开发之OC与swift开发混编教程,代理的相互调用,block的实现。OC调用Swift中的代理, OC调用Swift中的Block 闭包
    Git简单使用
    软考和软件设计师
    libstdc++适配Xcode10与iOS12
    Objective-C Block与函数指针比较
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9751249.html
Copyright © 2011-2022 走看看