P3924 康娜的线段树

题目描述

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

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

struct Segment_Tree{
#define lson (o<<1)
#define rson (o<<1|1)
int sumv[N<<2],minv[N<<2];
inline void pushup(int o){sumv[o]=sumv[lson]+sumv[rson];}
inline void build(int o,int l,int r){
if(l==r){sumv[o]=a[l];return;}
int mid=(l+r)>>1;
build(lson,l,mid);build(rson,mid+1,r);
pushup(o);
}
inline void change(int o,int l,int r,int q,int v){
if(l==r){sumv[o]+=v;return;}
int mid=(l+r)>>1;
if(q<=mid)change(lson,l,mid,q,v);
else change(rson,mid+1,r,q,v);
pushup(o);
}
}T;

在修改时,她会这么写:

for(int i=l;i<=r;i++)T.change(1,1,n,i,addv);

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

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

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

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

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

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

输入输出格式

输入格式:

第一行整数\(n,m,qwq\)表示线段树维护的原序列的长度,询问次数,分母。

第二行\(n\)个数,表示原序列。

接下来\(m\)行,每行三个数\(l,r,x\)表示对区间\([l,r]\)加上\(x\)

输出格式:

共\(m\)行,表示期望的权值和乘上\(qwq\)结果。

说明

对于30%的数据,保证 \(1 \leq n,m \leq 100\)

对于70%的数据,保证 \(1 \leq n,m, \leq 10^{5}\)

对于100%的数据,保证 \(1 \leq n,m \leq 10^6\)

\(-1000 \leq a_i,x \leq 1000\)


其实题目不难,然而我概率期望学的差,还是不怎么会做。

我们发现,其实每个叶子节点的贡献的不会变的,则第\(i\)个叶子节点贡献的次数是它之前的所有包含它的区间的贡献次数之和。

根据条件概率,每一个大区间出现的概率都是它的子区间的两倍,所以我们以最小的区间算做1,统计每个叶子节点的贡献次数,最后再除以\(\lceil logn \rceil\)即可。

具体实现可以直接模拟建树统计。

然后我们发现操作只有区间加和全局询问。

区间加我们可以通过叶子节点贡献次数前缀和维护全局偏移量。

复杂度:\(O(nlogn+m)\)


Code:

#include <cstdio>
#define ll long long
ll max(ll x,ll y){return x>y?x:y;}
const ll N=1000010;
ll dat[N],cnt[N],f[N],ans,QAQ,n,m,d,dep[N];
void build(ll l,ll r,ll Dep)
{
if(l==r)
{
dep[l]=Dep;
d=max(d,Dep);
return;
}
ll mid=l+r>>1;
build(l,mid,Dep+1);
build(mid+1,r,Dep+1);
}
void init()
{
scanf("%lld%lld%lld",&n,&m,&QAQ);
build(1,n,1);
for(ll i=1;i<=n;i++)
{
if(dep[i]==d)
cnt[i]=(1<<d)-1;
else
cnt[i]=(1<<d)-2;
scanf("%lld",dat+i);
f[i]=f[i-1]+cnt[i];
ans+=cnt[i]*dat[i];
}
}
void work()
{
ll l,r,x;
d=1<<d-1;
for(ll i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&l,&r,&x);
ans+=(f[r]-f[l-1])*x;
printf("%lld\n",(QAQ/d*ans));
}
}
int main()
{
init();
work();
return 0;
}

2018.7.21

最新文章

  1. leetcode 33. Search in Rotated Sorted Array
  2. 12 哈希表相关类——Live555源码阅读(一)基本组件类
  3. oracle中的自动增长
  4. .Net自帶Ajax和GridView
  5. mysql str_to_date字符串转换为日期
  6. 邻结矩阵的建立和 BFS,DFS;;
  7. 第一次尝试使用JAVA编写的ATM机程序
  8. Mysql时间戳开始时间1970-01-01 00:00:00和PHP date慢8小时
  9. 2015年最棒的10个 JavaScript 框架
  10. cocos2d学习笔录1
  11. With As 获取 id parentId 递归获取所有
  12. forEach、map、filter、some、every五个数组方法
  13. python 的日志logging模块学习
  14. 发现了一个非常棒的pyqt5的例子集
  15. Ubuntu下使用Sublime Text 3配置Python开发环境
  16. dojo下的dom按钮与dijit/form/Button
  17. ios 对于AFNetworking3.0的基本使用
  18. Gym 101194E / UVALive 7901 - Ice Cream Tower - [数学+long double][2016 EC-Final Problem E]
  19. mysql linux安装
  20. ORACLE与SQLSERVER数据转换

热门文章

  1. Android线程管理(一)&mdash;&mdash;线程通信
  2. PostFix使用dovecot支持POP3/IMAP收信
  3. python爬虫之requests库
  4. Openwrt能用的花生壳客户端
  5. Python教程 深入条件控制
  6. 基于腾讯云CLB实现K8S v1.10.1集群高可用+负载均衡
  7. spring第一章
  8. PRML学习笔记第一章
  9. Hexo博客 云服务器搭建
  10. tcp三次握手 四次挥手 (转)