题意
给定序列 (a),现在在 (a) 中随机选出一个可重集 (S)
(S) 有序,求
[sum_{i=1}^{|S|-1} S_i S_{i+1}
]
的期望,支持修改。
(n, q le 3 imes 10^5)
思路
首先集合数是 (2^n) ,转成数数。
然后发现求和之间没有什么关系,考虑对于每个 pair 计算贡献,即 (2^{n - (i-j+1)} a_i a_j),其中 ({a}) 有序
如果不带修改,这个用个前/后缀和维护就好。
支持修改的维护比较麻烦,但仔细想发现可以在线段树上直接维护,利用权值线段树将一个区间分成两个的特点分治维护。
对于每个线段树节点维护 (size),(a_i cdot 2^{i-1}),(a_i cdot 2^{size-i}) 和答案即可。
合并信息非常容易,对于叶子节点可能一个数字出现多次的情况,可以预处理同一个值的贡献次数,具体参见代码。(不过我这码风不能看啊)
Code
想清楚,实现并不难,不要拿到就写啊。
貌似有个 pypy
跑的比我快???
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
typedef long long ll;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
char getc () {return gc();}
inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0', x /= 10;while (qr) putc (qu[qr --]);}
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi; using io :: putc; using io :: print; using io :: getc;
template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}
const int mod = 1000000007;
inline int add(int x, int y){return x+y>=mod ? x+y-mod : x+y;}
inline int sub(int x, int y){return x-y<0 ? x-y+mod : x-y;}
inline int mul(int x, int y){return 1LL * x * y % mod;}
inline int power(int x, int y){
int res = 1;
for(; y; y>>=1, x = mul(x, x)) if(y & 1) res = mul(res, x);
return res;
}
inline int inv(int x){return power(x, mod - 2);}
const int N = 300005, Node = 2400005;
int p[N];
int pow2[N];
int n, q;
int v[N * 2], vc = 0;
int pos[N], val[N], single[N];
#define Rt 1, 1, vc
int pre[Node], suf[Node], sum[Node], sz[Node];
void modify(int x, int l, int r, int p, int d){
if(l == r){
sz[x] += d;
sum[x] = mul(mul(v[p], v[p]), single[sz[x]]);
if(d == 1) pre[x] = add(pre[x], mul(v[p], pow2[sz[x] - 1])), suf[x] = add(suf[x], mul(v[p], pow2[sz[x] - 1]));
else pre[x] = sub(pre[x], mul(v[p], pow2[sz[x]])), suf[x] = sub(suf[x], mul(v[p], pow2[sz[x]]));
return ;
}
int mid = (l + r) >> 1;
p <= mid ? modify(x << 1, l, mid, p, d) : modify(x << 1 | 1, mid + 1, r, p, d);
sz[x] = sz[x << 1] + sz[x << 1 | 1];
pre[x] = add(pre[x << 1], mul(pow2[sz[x << 1]], pre[x << 1 | 1]));
suf[x] = add(suf[x << 1 | 1], mul(pow2[sz[x << 1 | 1]], suf[x << 1]));
sum[x] = add(add(mul(sum[x << 1], pow2[sz[x << 1 | 1]]), mul(sum[x << 1 | 1], pow2[sz[x << 1]])), mul(pre[x << 1], suf[x << 1 | 1])); // 信息合并
}
#define Rt 1, 1, vc
int main(){
int allinv;
gi(n);
pow2[0] = 1;
for(int i=1; i<=n; i++)
pow2[i] = add(pow2[i-1], pow2[i-1]);
for(int i=2; i<=n; i++)
single[i] = add(add(single[i-1], single[i-1]), sub(pow2[i - 1], 1)); // 单点贡献
allinv = inv(pow2[n]);
for(int i=1; i<=n; i++) gi(p[i]), v[++vc] = p[i];
gi(q);
for(int i=1; i<=q; i++){
gi(pos[i]); gi(val[i]);
v[++vc] = val[i];
}
sort(v+1, v+1+vc);
vc = unique(v+1, v+1+vc) - v - 1;
for(int i=1; i<=n; i++){
p[i] = lower_bound(v+1, v+1+vc, p[i]) - v;
modify(Rt, p[i], 1);
}
print(mul(sum[1], allinv)); putc('
');
for(int i=1; i<=q; i++){
val[i] = lower_bound(v+1, v+1+vc, val[i]) - v;
modify(Rt, p[pos[i]], -1);
modify(Rt, val[i], 1);
p[pos[i]] = val[i];
print(mul(sum[1], allinv)); putc('
');
}
return 0;
}