挺妙的一个题。
本文不会带你卡精度,想卡可以看代码()
如果节点 \(i\)(注意不一定是叶子)深度为 \(depth_i\)(从 \(0\) 开始),维护的权值和为 \(sum_i\),则答案为:
但是这样依旧维护不了答案,因为一次修改(注意本题没有lazy) 会修改很多的节点。
然后考虑节点的权值和都来源于叶子节点(即维护区间长度为 \(1\))的权值。考虑仅用所有的叶子节点 \(i\) 表示出最后的期望:
也就是把每个节点的权值放在了叶子里面,第二个式子里一连串的分数,就分别代表了这个叶子的某个祖先被路过的概率。
所以对一个位置增加 \(x\) 的贡献是确定的。即对于位置 \(i\),如果增加了 \(x\),则总的答案增加 \(x\,\cdot f(i)\) ,然后 \(f(i)\) 在整个运行过程中始终不变,同时仅与 \(depth_i\) 有关。更具体地,\(f(i)=\sum_{j=0}^{depth_i}\frac{1}{2^j}\)。那么计算出 \(f\) 以后,维护 \(f\) 的前缀和,就可以 \(O(1)\) 回答一次操作过后的答案。
求 \(f\) 就必须先求出每个叶子节点的深度。考虑建出一颗线段树,在 \(O(n \log n)\) 的时间内可以求出,期望得到 70 pts。
其实开O2卡卡常,如果是考场加上ccf少爷机说不定就过了()
发现瓶颈在于求出每个叶子节点的深度,需要优化这个过程到 \(O(n)\) 级别的复杂度。
考虑建树过程中的划分方案是一样的,所以如果我们已经为一段长度为 \(k\) 的区间递归建完了树,那么对于其它长度为 \(k\) 的区间可以除掉递归,直接求深度。记忆化一下即可。有 \(n\) 个不同长度的区间,加上每个位置的深度只会被计算一次,可以在 \(O(n)\) 的时间内解决这个问题。如果理解困难建议看一下代码,非常简短。
所以这题就在 \(O(n)\) 的时间内解决了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const int MAXN=1e6+10;
ll n,m,qwq,a[MAXN],l[MAXN],r[MAXN],x[MAXN];
ll ans;
ll depth[MAXN],power[30],sum[30],pre[MAXN];
pi f[MAXN]; //记忆化
il void Read(ll& num){
char ch;
int flag=1;
while((ch=getchar()) && (ch<'0' || ch>'9') && (ch!='-'));
if(ch!='-')num=ch-'0';
else flag=-1;
while((ch=getchar()) && (ch>='0' && ch<='9'))num=num*10+ch-'0';
num*=flag;
}
void dfs(int l,int r,int d){
if(f[r-l+1]!=mp(0,0)){
rep(i,1,r-l+1){
depth[l+i-1]=d+(depth[f[r-l+1].fr+i-1]-f[r-l+1].se);
}
return;
}
f[r-l+1]=mp(l,d);
if(l==r){
depth[l]=d;
return;
}
int mid=(l+r)>>1;
dfs(l,mid,d+1);dfs(mid+1,r,d+1);
}
int main(){
power[0]=1;
rep(i,1,29)power[i]=power[i-1]*2;
Read(n);Read(m);Read(qwq);
qwq*=128;
rep(i,1,n){
Read(a[i]);
}
rep(i,1,m){
Read(l[i]);Read(r[i]);Read(x[i]);
}
dfs(1,n,0);
sum[0]=qwq;
rep(i,1,21){
sum[i]=sum[i-1]+qwq/power[i];
}
rep(i,1,n){
pre[i]=pre[i-1]+sum[depth[i]];
ans+=sum[depth[i]]*a[i];
}
rep(i,1,m){
ans+=(pre[r[i]]-pre[l[i]-1])*x[i];
printf("%lld\n",ans/128);
}
return 0;
}