【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=3786
【题解】
用splay维护欧拉序,修改相当于将一段区间移到另一个位置。子树加就是区间加,查询链的答案相当于一段前缀和,都是splay基本操作。
时间复杂度
O(M∗logN)
O
(
M
∗
l
o
g
N
)
【代码】
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj3786]
Points : splay
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 200005
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
struct Edge{
int data, next;
}e[N * 2];
struct Tree{
ll sum, num1, num0, tag, now;
int pl, pr, fa, f;
}T[N];
int id[N], num, place, h[N], head[N], in[N], out[N], rt, st[N], top, n, m;
void build(int u, int v){
e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
id[++num] = x; in[x] = num;
for (int ed = head[x]; ed != 0; ed = e[ed].next)
if (e[ed].data != fa)
dfs(e[ed].data, x);
id[++num] = -x; out[x] = num;
}
void pushtag(int p){
if (p == 0 || T[p].tag == 0) return;
if (T[p].pl != 0){
int tmp = T[p].pl;
T[tmp].sum = T[tmp].sum + (T[tmp].num1 - T[tmp].num0) * T[p].tag;
T[tmp].now += T[p].tag * T[tmp].f;
T[tmp].tag += T[p].tag;
}
if (T[p].pr != 0){
int tmp = T[p].pr;
T[tmp].sum = T[tmp].sum + (T[tmp].num1 - T[tmp].num0) * T[p].tag;
T[tmp].now += T[p].tag * T[tmp].f;
T[tmp].tag += T[p].tag;
}
T[p].tag = 0;
}
void reget(int p){
if (p == 0) return;
T[p].num0 = T[T[p].pl].num0 + T[T[p].pr].num0 + (id[p] < 0);
T[p].num1 = T[T[p].pl].num1 + T[T[p].pr].num1 + (id[p] > 0);
T[p].sum = T[T[p].pl].sum + T[T[p].pr].sum + T[p].now;
}
void build(int &p, int l, int r, int fa){
int mid = (l + r) / 2;
p = mid; T[p].fa = fa;
if (id[mid] > 0) T[p].f = 1; if (id[mid] < 0) T[p].f = -1;
if (T[p].f > 0) T[p].num1++; if (T[p].f < 0) T[p].num0++;
T[p].now = T[p].f * h[abs(id[mid])];
if (l < mid) build(T[p].pl, l, mid - 1, p);
if (mid < r) build(T[p].pr, mid + 1, r, p);
reget(p);
}
void zig(int x){
int y = T[x].fa;
if (T[T[y].fa].pl == y)
T[T[y].fa].pl = x;
else T[T[y].fa].pr = x;
T[x].fa = T[y].fa;
T[T[x].pr].fa = y, T[y].pl = T[x].pr;
T[y].fa = x; T[x].pr = y;
reget(y); reget(x);
}
void zag(int x){
int y = T[x].fa;
if (T[T[y].fa].pl == y)
T[T[y].fa].pl = x;
else T[T[y].fa].pr = x;
T[x].fa = T[y].fa;
T[T[x].pl].fa = y, T[y].pr = T[x].pl;
T[y].fa = x; T[x].pl = y;
reget(y); reget(x);
}
void solve(int x, int w){
if (x == 0) return;
pushtag(x);
solve(T[x].pl, w);
solve(T[x].pr, w);
}
void splay(int x){
pushtag(x);
if (rt == x) return;
int tmp = x;
st[top = 1] = tmp;
while (T[tmp].fa != 0) st[++top] = tmp = T[tmp].fa;
for (int i = top; i >= 1; i--) pushtag(st[i]);
pushtag(T[x].pl), pushtag(T[x].pr);
while (T[x].fa != rt){
int y = T[x].fa;
if (T[y].fa == rt){
if (T[y].pl == x)
zig(x); else zag(x);
continue;
}
if (T[T[y].fa].pl == y){
if (T[y].pl == x) zig(y), zig(x);
else zag(x), zig(x);
}
else if (T[y].pl == x) zig(x), zag(x);
else zag(y), zag(x);
}
if (T[rt].pl == x)
zig(x); else zag(x);
rt = x;
}
int findnex(int x){
splay(x);
x = T[x].pr;
while (T[x].pl != 0) x = T[x].pl;
return x;
}
int findpre(int x){
splay(x);
x = T[x].pl;
while (T[x].pr != 0) x = T[x].pr;
return x;
}
int main(){
freopen("bzoj3786.in", "r", stdin);
freopen("bzoj3786.out", "w", stdout);
n = read(); num = 1;
for (int i = 2; i <= n; i++){
int u = read();
build(i, u); build(u, i);
}
for (int i = 1; i <= n; i++) h[i] = read();
dfs(1, 0);
build(rt, 1, num + 1, 0);
m = read();
char opt;
for (int i = 1; i <= m; i++){
scanf("\n%c", &opt);
if (opt == 'Q'){
int x = read();
splay(findnex(in[x]));
pushtag(T[rt].pl);
printf("%lld\n", T[T[rt].pl].sum);
}
if (opt == 'F'){
int x = read(), w = read();
int r = findnex(out[x]), l = findpre(in[x]);
splay(r), splay(l);
int tmp = T[T[rt].pr].pl;
T[tmp].sum = T[tmp].sum + (T[tmp].num1 - T[tmp].num0) * w;
T[tmp].now += w * T[tmp].f;
T[tmp].tag += w;
}
if (opt == 'C'){
int x = read(), v = read();
int r = findnex(out[x]), l = findpre(in[x]);
splay(r), splay(l);
int tmp = T[T[rt].pr].pl;
T[tmp].fa = 0; T[T[rt].pr].pl = 0;
pushtag(tmp);
reget(T[rt].pr); reget(rt);
r = findnex(in[v]), l = in[v];
splay(r); splay(l);
T[tmp].fa = T[rt].pr;
T[T[rt].pr].pl = tmp;
reget(T[rt].pr); reget(rt);
}
}
return 0;
}