BZOJ#3786. 星系探索(平衡樹,fhq-treap,弱化版ETT)
BZOJ#3786. 星系探索
Solution
子樹加,換
f
a
t
h
e
r
father
father(保證還是樹),詢問到根路徑和。
樹上路徑求和不好動態維護,於是轉化到序列上,維護一個括號序,
d
f
n
dfn
dfn處貢獻為
w
w
w,
f
n
s
fns
fns處貢獻為
−
w
-w
−w,一段路徑
(
x
,
y
)
(x,y)
(x,y)的和相當於序列上
d
f
n
x
dfn_x
dfnx到
d
f
n
y
dfn_y
dfny的貢獻和。
於是子樹加相當於區間加,交換子樹相當於在括號序上取出一個區間插入到其他地方去。
這個可以直接用平衡樹維護,這裡用的是
f
h
q
−
t
r
e
a
p
fhq-treap
我們在 f h q − t r e a p fhq-treap fhq−treap中節點的下標對應的是原樹的括號序編號,即 d f n x dfn_x dfnx在 t r e a p treap treap上對應 d f n x dfn_x dfnx號節點,在 s p l i t split split時,當前的括號序為中序遍歷 t r e a p treap treap後得到的節點編號序列。需要求出節點在 t r e a p treap treap上的 r a n k rank rank,然後再按 r a n k rank rank分成兩棵子樹。
剩下的就是
t
r
e
a
p
treap
時間複雜度 O ( n l g n ) O(nlgn) O(nlgn)。
Code
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
using namespace std;
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
int f=1,x=0; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
return x*f;
}
struct fhq_treap
{
ll a[MAXN],sum[MAXN],tag[MAXN];
int b[MAXN],sz[MAXN],p[MAXN],num[MAXN],fa[MAXN],ch[MAXN][2],rt;
void up(int x)
{
sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
num[x]=num[ch[x][0]]+num[ch[x][1]]+p[x];
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+a[x];
if (ch[x][0]) fa[ch[x][0]]=x;
if (ch[x][1]) fa[ch[x][1]]=x;
}
void puttag(int x,ll y)
{
if (!x) return;
tag[x]+=y,a[x]+=y*p[x],sum[x]+=y*num[x];
}
void down(int x)
{
if (!x||tag[x]==0) return;
puttag(ch[x][0],tag[x]),puttag(ch[x][1],tag[x]),tag[x]=0;
}
int nwnode(int id,int opt,int x)
{
p[id]=num[id]=opt;
a[id]=sum[id]=opt*x;
b[id]=rand(),sz[id]=1;
return id;
}
void split(int nw,int k,int &x,int &y)
{
if (!nw) x=y=0;
else
{
down(nw);
if (k<=sz[ch[nw][0]]) y=nw,split(ch[nw][0],k,x,ch[nw][0]);
else x=nw,split(ch[nw][1],k-sz[ch[nw][0]]-1,ch[nw][1],y);
up(nw);
}
}
int merge(int x,int y)
{
if (!x||!y) return x|y;
down(x),down(y);
if (b[x]<b[y]) return ch[x][1]=merge(ch[x][1],y),up(x),x;
else return ch[y][0]=merge(x,ch[y][0]),up(y),y;
}
int rank(int x)
{
int rk=sz[ch[x][0]]+1;
while (fa[x])
{
if (x==ch[fa[x]][1]) rk+=sz[ch[fa[x]][0]]+1;
x=fa[x];
}
return rk;
}
ll Query(int x)
{
int A,B;
split(rt,rank(x),A,B);
ll ans=sum[A];
rt=merge(A,B);
return ans;
}
void Swap(int l,int r,int x)
{
int A,B,C,D;
l=rank(l),r=rank(r),x=rank(x);
if (x<=l-1) //1...x...l...r...n
{
split(rt,r,A,D);
split(A,l-1,A,B);
split(A,x,A,C);
rt=merge(merge(merge(A,B),C),D);
}
else
{
split(rt,x,A,D); //1...l...r...x...n
split(A,r,A,B);
split(A,l-1,A,C);
rt=merge(merge(merge(A,B),C),D);
}
}
void Update(int l,int r,int y)
{
int A,B,C;
l=rank(l),r=rank(r);
split(rt,r,A,C);
split(A,l-1,A,B);
puttag(B,y);
rt=merge(merge(A,B),C);
}
} T;
vector<int> e[MAXN];
int dfn[MAXN],fns[MAXN],w[MAXN],DFN=0;
void dfs(int x,int father)
{
dfn[x]=++DFN;
T.rt=T.merge(T.rt,T.nwnode(DFN,1,w[x]));
for (auto v:e[x]) if (v!=father) dfs(v,x);
fns[x]=++DFN;
T.rt=T.merge(T.rt,T.nwnode(DFN,-1,w[x]));
}
signed main()
{
srand(time(0));
int n=read();
for (int i=2;i<=n;i++) e[read()].PB(i);
for (int i=1;i<=n;i++) w[i]=read();
dfs(1,0);
int Case=read();
while (Case--)
{
int x,y; char c;
scanf("%c",&c);
if (c=='Q') x=read(),printf("%lld\n",T.Query(dfn[x]));
else if (c=='C') x=read(),y=read(),T.Swap(dfn[x],fns[x],dfn[y]);
else x=read(),y=read(),T.Update(dfn[x],fns[x],y);
}
return 0;
}