好久没有写过数据结构题目了,果然还是太不自信。实际上就是要求统计一个式子:
\(\sum (c[k]*p[k] - C)^{2}\)
拆开,分别统计和与平方和
\(co[k] * \sum p[k]^{2} - 2 * C * co[k] \sum p[k] + \sum C ^{2}\)
显然可以用树链剖分 + 线段树维护
平方和在区间 + 1的时候直接用 \((x + 1) ^ {2} = x^2 + 2 * x + 1\) 计算即可。
至于不同的口味的问题,我们给每个口味都开一线段树,动态开点~听起来虽然复杂,但代码实际上超短。◕ᴗ◕。
#include <bits/stdc++.h> using namespace std; #define maxn 3000000 #define int long long #define db double int n, m, q, C, cnt, f[maxn], co[maxn], dfn[maxn]; int size[maxn], hson[maxn], top[maxn], fa[maxn]; int root[maxn], mark[maxn * 2], cal[maxn * 2], cal2[maxn * 2], son[maxn * 2][2]; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * k; } struct edge { int cnp, to[maxn], last[maxn], head[maxn]; edge() { cnp = 2; } void add(int u, int v) { to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++; } }E1; void dfs(int u) { size[u] = 1; int mx = 0, hs = 0; for(int i = E1.head[u]; i; i = E1.last[i]) { int v = E1.to[i]; fa[v] = u; dfs(v); size[u] += size[v]; if(size[v] >= mx) mx = size[v], hs = v; } hson[u] = hs; } void dfs2(int u, int anc) { dfn[u] = ++ cnt, top[u] = anc; if(hson[u]) dfs2(hson[u], anc); for(int i = E1.head[u]; i; i = E1.last[i]) if(E1.to[i] != hson[u]) dfs2(E1.to[i], E1.to[i]); } void Add(int &p, int l, int r, int x) { if(!p) p = ++ cnt; mark[p] += x; cal2[p] += cal[p] * x + (r - l + 1) * x * x; cal[p] += (r - l + 1) * x * 2; } void Push_down(int p, int l, int r) { int mid = (l + r) >> 1; if(!mark[p]) return; Add(son[p][0], l, mid, mark[p]); Add(son[p][1], mid + 1, r, mark[p]); mark[p] = 0; } void Push_Up(int p) { int l = son[p][0], r = son[p][1]; cal2[p] = cal2[l] + cal2[r]; cal[p] = cal[l] + cal[r]; } void Update(int &p, int l, int r, int L, int R, int x) { if(L > R || l > r) return; if(!p) p = ++ cnt; if(L <= l && R >= r) { Add(p, l, r, x); return; } Push_down(p, l, r); int mid = (l + r) >> 1; if(L <= mid) Update(son[p][0], l, mid, L, R, x); if(R > mid) Update(son[p][1], mid + 1, r, L, R, x); Push_Up(p); } void T_Update(int k, int u, int x) { for(; u; u = fa[top[u]]) Update(root[k], 1, n, dfn[top[u]], dfn[u], x); } int Cal(int p) { return co[p] * co[p] * cal2[root[p]] - cal[root[p]] * C * co[p] + n * C * C; } signed main() { n = read(), m = read(), q = read(), C = read(); for(int i = 1; i <= n; i ++) f[i] = read(); for(int i = 2; i <= n; i ++) { int x = read(); E1.add(x, i); } for(int i = 1; i <= m; i ++) co[i] = read(); dfs(1), dfs2(1, 1), cnt = m; for(int i = 1; i <= m; i ++) root[i] = i; for(int i = 1; i <= n; i ++) T_Update(f[i], i, 1); for(int i = 1; i <= q; i ++) { int opt = read(); if(opt == 1) { int x = read(), k = read(); T_Update(f[x], x, -1), T_Update(f[x] = k, x, 1); } else { int k = read(); printf("%lf\n", (db) Cal(k) / (db) n); } } return 0; }