树链剖分模板

摘要:

本以为自己学会了树剖,但最后发现我还是只会用树剖求lca,至于最后的线段树。。。

完全没有用到top,fa,son数组!

也就是说我学的树剖是错的!

所以赶紧来补一波板子:

题目:

这是一道模板题。

给定一棵n个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值。下面依次进行 m 个操作,操作分为如下五种类型:

  • 换根:将一个指定的节点设置为树的新根。

  • 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。

  • 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。

  • 询问路径:询问某条路径上节点的权值和。

  • 询问子树:询问某个子树内节点的权值和。

输入格式

第一行一个整数n,表示节点的个数。

第二行n个整数表示第i个节点的初始权值$a_i$

第三行n-1个整数,表示i+1号节点的父节点编号$f_{i+1}(1\leqslant f_{i+1}\leqslant n)$

第四行一个整数m,表示操作个数。

接下来m行,每行第一个整数表示操作类型编号:$1\leqslant u,v\leqslant n$

  若类型为1,则接下来一个整数u,表示新根的编号。

  若类型为2,则接下来三个整数u,v,k,分别表示路径两端的节点编号以及增加的权值。

  若类型为3,则接下来两个整数u,k,分别表示子树根节点编号以及增加的权值。

  若类型为4,则接下来两个整数u,v,表示路径两端的节点编号。

  若类型为5,则接下来一个整数u,表示子树根节点编号。

输出格式

对于每一个类型为45的操作,输出一行一个整数表示答案。

样例

样例输入

6
1 2 3 4 5 6
1 2 1 4 4
6
4 5 6
2 2 4 1
5 1
1 4
3 1 2
4 2 5

样例输出

15
24
19

数据范围与提示

对于 100% 的数据,$1\leqslant n,m,k,a_i\leqslant 10^5$

数据有一定梯度。

有不同板子:

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define Rint register int
#define mem(a,b) memset(a,(b),sizeof(a))
#define Temp template<typename T>
using namespace std;
typedef long long LL;
Temp inline void read(T &x){
    x=0;T w=1,ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
    x=x*w;
}

#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)

const int maxn=200000+10;
int n,m,r,mod;
//见题意 
int e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
//链式前向星数组,w[]、wt[]初始点权数组 
int a[maxn<<2],laz[maxn<<2];
//线段树数组、lazy操作 
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn]; 
//son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点 
int res=0;
//查询答案 

inline void add(int x,int y){//链式前向星加边 
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
}
//-------------------------------------- 以下为线段树 
inline void pushdown(int rt,int lenn){
    laz[rt<<1]+=laz[rt];
    laz[rt<<1|1]+=laz[rt];
    a[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
    a[rt<<1|1]+=laz[rt]*(lenn>>1);
    a[rt<<1]%=mod;
    a[rt<<1|1]%=mod;
    laz[rt]=0;
}

inline void build(int rt,int l,int r){
    if(l==r){
        a[rt]=wt[l];
        if(a[rt]>mod)a[rt]%=mod;
        return;
    }
    build(lson);
    build(rson);
    a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}

inline void query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){res+=a[rt];res%=mod;return;}
    else{
        if(laz[rt])pushdown(rt,len);
        if(L<=mid)query(lson,L,R);
        if(R>mid)query(rson,L,R);
    }
}

inline void update(int rt,int l,int r,int L,int R,int k){
    if(L<=l&&r<=R){
        laz[rt]+=k;
        a[rt]+=k*len;
    }
    else{
        if(laz[rt])pushdown(rt,len);
        if(L<=mid)update(lson,L,R,k);
        if(R>mid)update(rson,L,R,k);
        a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
    }
}
//---------------------------------以上为线段树 
inline int qRange(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){//当两个点不在同一条链上 
        if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
        res=0;
        query(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
        ans+=res;
        ans%=mod;//按题意取模 
        x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
    }
    //直到两个点处于一条链上
    if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
    res=0;
    query(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
    ans+=res;
    return ans%mod;
}

inline void updRange(int x,int y,int k){//同上 
    k%=mod;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(1,1,n,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    update(1,1,n,id[x],id[y],k);
}

inline int qSon(int x){
    res=0;
    query(1,1,n,id[x],id[x]+siz[x]-1);//子树区间右端点为id[x]+siz[x]-1 
    return res;
}

inline void updSon(int x,int k){//同上 
    update(1,1,n,id[x],id[x]+siz[x]-1,k);
}

inline void dfs1(int x,int f,int deep){//x当前节点,f父亲,deep深度 
    dep[x]=deep;//标记每个点的深度 
    fa[x]=f;//标记每个点的父亲 
    siz[x]=1;//标记每个非叶子节点的子树大小 
    int maxson=-1;//记录重儿子的儿子数 
    for(Rint i=beg[x];i;i=nex[i]){
        int y=to[i];
        if(y==f)continue;//若为父亲则continue 
        dfs1(y,x,deep+1);//dfs其儿子 
        siz[x]+=siz[y];//把它的儿子数加到它身上 
        if(siz[y]>maxson)son[x]=y,maxson=siz[y];//标记每个非叶子节点的重儿子编号 
    }
}

inline void dfs2(int x,int topf){//x当前节点,topf当前链的最顶端的节点 
    id[x]=++cnt;//标记每个点的新编号 
    wt[cnt]=w[x];//把每个点的初始值赋到新编号上来 
    top[x]=topf;//这个点所在链的顶端 
    if(!son[x])return;//如果没有儿子则返回 
    dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理 
    for(Rint i=beg[x];i;i=nex[i]){
        int y=to[i];
        if(y==fa[x]||y==son[x])continue;
        dfs2(y,y);//对于每一个轻儿子都有一条从它自己开始的链 
    }
}

int main(){
    read(n);read(m);read(r);read(mod);
    for(Rint i=1;i<=n;i++)read(w[i]);
    for(Rint i=1;i<n;i++){
        int a,b;
        read(a);read(b);
        add(a,b);add(b,a);
    }
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n);
    while(m--){
        int k,x,y,z;
        read(k);
        if(k==1){
            read(x);read(y);read(z);
            updRange(x,y,z);
        }
        else if(k==2){
            read(x);read(y);
            printf("%d\n",qRange(x,y));
        }
        else if(k==3){
            read(x);read(y);
            updSon(x,y);
        }
        else{
            read(x);
            printf("%d\n",qSon(x));
        }
    }
}

还有个链接:https://www.cnblogs.com/chinhhh/p/7965433.html#build

这个:(倍增)

#include<cstdio>
#include<vector>
#include<algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
using namespace std;
const int N=1e5+5;
int son[N],siz[N],dep[N],top[N],idx[N],rev[N],num;
int lg[N],f[N][20];
ll sum[N<<2],add[N<<2];
int n,q,op,a,b,c,w[N],root=1;
vector<int>G[N];
struct TREE{
	inline void pushup(int rt) {sum[rt]=sum[rt<<1]+sum[rt<<1|1];}
	inline void build(int l,int r,int rt)
	{
		add[rt]=0;
		if(l==r) {sum[rt]=w[rev[l]];return;}
		int m=(l+r)>>1;
		build(lson),build(rson);
		pushup(rt);
	}
	inline void pushdown(int rt,int m)
	{
		if(add[rt])
		{
			add[rt<<1]+=add[rt],add[rt<<1|1]+=add[rt];
			sum[rt<<1]+=add[rt]*(m-(m>>1));
			sum[rt<<1|1]+=add[rt]*(m>>1);
			add[rt]=0;
		}
	}
	inline void update(int L,int R,int val,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			sum[rt]+=(ll)val*(r-l+1);
			add[rt]+=val;
			return;
		}
		pushdown(rt,r-l+1);
		int m=(l+r)>>1;
		if(L<=m) update(L,R,val,lson);
		if(R>m) update(L,R,val,rson);
		pushup(rt);
	}
	inline ll query(int L,int R,int l,int r,int rt)
	{
		if(L<=l && r<=R) return sum[rt];
		pushdown(rt,r-l+1);
		int m=(l+r)>>1;ll ans=0;
		if(L<=m) ans+=query(L,R,lson);
		if(R>m) ans+=query(L,R,rson);
		return ans;
	}
}T;
struct Tree{
	inline void dfs1(int x)
	{
		dep[x]=dep[f[x][0]]+1,siz[x]=1;
		for(int i=1;(1<<i)<=dep[x];++i) f[x][i]=f[f[x][i-1]][i-1];
		for(int i=0;i<(int)G[x].size();++i)
		{
			int v=G[x][i];
			if(v==f[x][0]) continue;
			dfs1(v),siz[x]+=siz[v];
			if(!son[x] || siz[v]>siz[son[x]]) son[x]=v;
		}
	}
	inline void dfs2(int x,int t)
	{
		top[x]=t,idx[x]=++num,rev[num]=x;
		if(son[x]) dfs2(son[x],t);
		for(int i=0;i<(int)G[x].size();++i)
		{
			int v=G[x][i];
			if(v==f[x][0] || v==son[x]) continue;
			dfs2(v,v);
		}
	}
	inline int lca(int x, int y)
	{
	    if(dep[x]<dep[y]) swap(x, y);
	    for(int i=18;i>=0;--i)
	    	if(dep[f[x][i]]>dep[y]) x=f[x][i];
	    if(f[x][0]==y) return x;
	    if(dep[f[x][0]]>=dep[y]) x=f[x][0];
		for(int i=lg[dep[x]]-1;i>=0;--i)
			if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
	    return x;
	}
	inline void update_subtree(int x,int z)
	{
		if(x==root) {T.update(1,n,z,1,n,1);return;}
		int d=lca(x,root);
//		printf("test:%d %d %d\n",x,root,d);
		if(f[d][0]==x) T.update(1,n,z,1,n,1),T.update(idx[d],idx[d]+siz[d]-1,-z,1,n,1);
		else T.update(idx[x],idx[x]+siz[x]-1,z,1,n,1);
	}
	inline ll query_subtree(int x)
	{
		if(x==root) return T.query(1,n,1,n,1);
		int d=lca(x,root);
//		printf("test2:%d %d %d\n",x,root,d);
		if(f[d][0]==x) return T.query(1,n,1,n,1)-T.query(idx[d],idx[d]+siz[d]-1,1,n,1);
		else return T.query(idx[x],idx[x]+siz[x]-1,1,n,1);
	}
	inline void update_path(int x,int y,int z)
	{
		while(top[x]^top[y])
		{
			if(dep[top[x]]<dep[top[y]]) swap(x,y);
			T.update(idx[top[x]],idx[x],z,1,n,1);
			x=f[top[x]][0];
		}
		if(dep[x]>dep[y]) swap(x,y);
		T.update(idx[x],idx[y],z,1,n,1);
	}
	inline ll query_path(int x,int y)
	{
		ll ans=0;
		while(top[x]^top[y])
		{
			if(dep[top[x]]<dep[top[y]]) swap(x,y);
			ans+=T.query(idx[top[x]],idx[x],1,n,1);
			x=f[top[x]][0];
		}
		if(dep[x]>dep[y]) swap(x,y);
		ans+=T.query(idx[x],idx[y],1,n,1);
		return ans;
	}
}t;
int main()
{
//	freopen("tree1.in","r",stdin);
//	freopen("tree.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&w[i]),lg[i]=lg[i>>1]+1;
	for(int i=2;i<=n;++i)
		scanf("%d",&f[i][0]),
		G[f[i][0]].push_back(i),G[i].push_back(f[i][0]);
	scanf("%d",&q);
	t.dfs1(1),t.dfs2(1,1),T.build(1,n,1);
	while(q--)
	{
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d",&a);
			root=a;
		}
		if(op==2)
		{
			scanf("%d%d%d",&a,&b,&c);
			t.update_path(a,b,c);
		}
		if(op==3)
		{
			scanf("%d%d",&a,&b);
			t.update_subtree(a,b);
		}
		if(op==4)
		{
			scanf("%d%d",&a,&b);
			printf("%lld\n",t.query_path(a,b));
		}
		if(op==5)
		{
			scanf("%d",&a);
			printf("%lld\n",t.query_subtree(a));
		}
//		printf("root:%d\n",root);
	}
	return 0;
}

还有:(努力想找一个和自己码风相似的)

#include <cstdio>
#include <algorithm>
using namespace std;
#define lson(x) (x << 1)
#define rson(x) (x << 1 | 1)
#define int long long
const int maxn = 500050;
struct Edge {
    int to, nxt;
} edge[maxn << 1];
struct point {
    int val, add;
} e[maxn << 2];
int n, q, root = 1, ecnt, cnt;
int head[maxn], a[maxn], b[maxn];
int par[maxn], size[maxn], dep[maxn], son[maxn], id[maxn], top[maxn];
namespace segment_tree {
	void build(int x, int l, int r) {
		e[x].add = 0;
		if (l == r)
		    e[x].val = a[l];
		else {
		    int mid = (l + r) >> 1;
		    build(lson(x), l, mid);
		    build(rson(x), mid + 1, r);
		    e[x].val = e[lson(x)].val + e[rson(x)].val;
		}
	}
	void pushdown(int x, int l, int r) {
		int mid = (l + r) >> 1;
		e[lson(x)].val += (mid - l + 1) * e[x].add;
		e[rson(x)].val += (r - mid) * e[x].add;
		e[lson(x)].add += e[x].add;
		e[rson(x)].add += e[x].add;
		e[x].add = 0;
	}
	void update_addtag(int x, int stdl, int stdr, int l, int r, int k) {
		if (r < stdl || stdr < l)
		    return;
		if (l <= stdl && stdr <= r) {
		    e[x].val += k * (stdr - stdl + 1);
		    e[x].add += k;
		    return;
		}
		pushdown(x, stdl, stdr);
		int mid = (stdl + stdr) >> 1;
		update_addtag(lson(x), stdl, mid, l, r, k);
		update_addtag(rson(x), mid + 1, stdr, l, r, k);
		e[x].val = e[lson(x)].val + e[rson(x)].val;
	}
	int query(int x, int stdl, int stdr, int l, int r) {
		if (r < stdl || stdr < l)
		    return 0;
		if (l <= stdl && stdr <= r)
		    return e[x].val;
		pushdown(x, stdl, stdr);
		int mid = (stdl + stdr) >> 1;
		return query(lson(x), stdl, mid, l, r) + query(rson(x), mid + 1, stdr, l, r);
	}
}  // namespace segment_tree
using namespace segment_tree;
namespace hcp {
	void add(int x, int y) {
		edge[++ecnt].to = y;
		edge[ecnt].nxt = head[x];
		head[x] = ecnt;
	}
	void dfs1(int x) {
		size[x] = 1;
		dep[x] = dep[par[x]] + 1;
		for (int i = head[x]; i; i = edge[i].nxt) {
		    int t = edge[i].to;
		    if (t == par[x])
		        continue;
		    par[t] = x;
		    dfs1(t);
		    size[x] += size[t];
		    if (!son[x] || size[son[x]] < size[t])
		        son[x] = t;
		}
	}
	void dfs2(int x, int y) {
		top[x] = y;
		id[x] = ++cnt, a[cnt] = b[x];
		if (son[x])
		    dfs2(son[x], y);
		for (int i = head[x]; i; i = edge[i].nxt) {
		    int t = edge[i].to;
		    if (t == par[x] || t == son[x])
		        continue;
		    dfs2(t, t);
		}
	}
	int lca(int x, int y) {
		while (top[x] != top[y]) {
		    if (dep[top[x]] < dep[top[y]])
		        swap(x, y);
		    x = par[top[x]];
		}
		if (dep[x] > dep[y])
		    swap(x, y);
		return x;
	}
	int findson(int x, int root) {
		while (top[root] != top[x]) {
		    if (par[top[root]] == x)
		        return top[root];
		    root = par[top[root]];
		}
		return son[x];
	}
}  // namespace hcp
using namespace hcp;
namespace solve_all {
	void update_path(int x, int y, int val) {
		while (top[x] != top[y]) {
		    if (dep[top[x]] < dep[top[y]])
		        swap(x, y);
		    update_addtag(1, 1, n, id[top[x]], id[x], val);
		    x = par[top[x]];
		}
		if (dep[x] > dep[y])
		    swap(x, y);
		update_addtag(1, 1, n, id[x], id[y], val);
	}
	void update_subtree(int x, int val) {
		if (lca(x, root) != x)
		    update_addtag(1, 1, n, id[x], id[x] + size[x] - 1, val);
		else if (x == root)
		    update_addtag(1, 1, n, 1, n, val);
		else {
		    int s = findson(x, root);
		    update_addtag(1, 1, n, 1, id[s] - 1, val);
		    if (id[s] + size[s] <= n)
		        update_addtag(1, 1, n, id[s] + size[s], n, val);
		}
	}
	int query_path(int x, int y) {
		int ans = 0;
		while (top[x] != top[y]) {
		    if (dep[top[x]] < dep[top[y]])
		        swap(x, y);
		    ans += query(1, 1, n, id[top[x]], id[x]);
		    x = par[top[x]];
		}
		if (dep[x] > dep[y])
		    swap(x, y);
		ans += query(1, 1, n, id[x], id[y]);
		return ans;
	}
	int query_subtree(int x) {
		int ans = 0;
		if (lca(x, root) != x)
		    ans += query(1, 1, n, id[x], id[x] + size[x] - 1);
		else if (x == root)
		    ans += query(1, 1, n, 1, n);
		else {
		    int s = findson(x, root);
		    ans += query(1, 1, n, 1, id[s] - 1);
		    if (id[s] + size[s] <= n)
		        ans += query(1, 1, n, id[s] + size[s], n);
		}
		return ans;
	}
}  // namespace solve_all
using namespace solve_all;
signed main() {
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) scanf("%lld", &b[i]);
    for (int i = 2; i <= n; i++) {
        int x;
        scanf("%lld", &x);
        add(x, i), add(i, x);
    }
    dfs1(1);
    dfs2(1, 1);
    build(1, 1, n);
    scanf("%lld", &q);
    while (q--) {
        int opt, x, y, z;
        scanf("%lld", &opt);
        if (opt == 1)
            scanf("%lld", &root);
        if (opt == 2)
            scanf("%lld%lld%lld", &x, &y, &z), update_path(x, y, z);
        if (opt == 3)
            scanf("%lld%lld", &x, &y), update_subtree(x, y);
        if (opt == 4)
            scanf("%lld%lld", &x, &y), printf("%lld\n", query_path(x, y));
        if (opt == 5)
            scanf("%lld", &x), printf("%lld\n", query_subtree(x));
    }
    return 0;
}

还有用树状数组的:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100005
int n, m, root = 1, a[N];
int head[N];
struct edgeType {
    int to, next;
} edge[N << 1];
inline void addEdge(int from, int to) {
    static int cnt = 0;
    edge[++cnt] = (edgeType){ to, head[from] };
    head[from] = cnt;
}
class BinaryIndexedTree {
private:
    long long c[2][N];
    inline int lowbit(int x) { return x & (-x); }
    inline void update(int x, long long v) {
        for (int i = x; i <= n; i += lowbit(i)) c[0][i] += v, c[1][i] += x * v;
    }
    inline long long query(int x) {
        long long ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) ans += (x + 1) * c[0][i] - c[1][i];
        return ans;
    }

public:
    inline void update(int l, int r, long long v) {
        update(l, v);
        update(r + 1, -v);
    }
    inline long long query(int l, int r) { return query(r) - query(l - 1); }
} BIT;
class TreeChain {
private:
    int root, parent[N], size[N], depth[N], son[N], top[N], tid[N], ted[N];
    inline void dfsPre(int u, int p, int d) {
        parent[u] = p;
        depth[u] = d;
        size[u] = 1;
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (v == p)
                continue;
            dfsPre(v, u, d + 1);
            size[u] += size[v];
            if (size[v] > size[son[u]])
                son[u] = v;
        }
    }
    inline void dfsTop(int u, int tp) {
        static int dfsClock = 0;
        top[u] = tp;
        tid[u] = ++dfsClock;
        if (son[u])
            dfsTop(son[u], tp);
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (v == parent[u] || v == son[u])
                continue;
            dfsTop(v, v);
        }
        ted[u] = dfsClock;
    }
    inline int reach(int x, int y) {
        int ans = 0;
        while (top[x] != top[y]) {
            ans = top[x];
            x = parent[top[x]];
        }
        return x == y ? ans : son[y];
    }

public:
    inline void init(int rt) {
        root = rt;
        dfsPre(root, 0, 1);
        dfsTop(root, root);
    }
    inline void changeRoot(int rt) { root = rt; }
    inline void updateInit(int x, int v) { BIT.update(tid[x], tid[x], v); }
    inline void updateRoute(int x, int y, int z) {
        while (top[x] != top[y]) {
            if (depth[top[x]] < depth[top[y]])
                std::swap(x, y);
            BIT.update(tid[top[x]], tid[x], z);
            x = parent[top[x]];
        }
        if (depth[x] > depth[y])
            std::swap(x, y);
        BIT.update(tid[x], tid[y], z);
    }
    inline long long queryRoute(int x, int y) {
        long long ans = 0;
        while (top[x] != top[y]) {
            if (depth[top[x]] < depth[top[y]])
                std::swap(x, y);
            ans += BIT.query(tid[top[x]], tid[x]);
            x = parent[top[x]];
        }
        if (depth[x] > depth[y])
            std::swap(x, y);
        return ans + BIT.query(tid[x], tid[y]);
    }
    inline void updateSubtree(int x, int z) {
        if (x == root)
            BIT.update(1, n, z);
        else if (tid[x] <= tid[root] && ted[x] >= ted[root]) {
            int t = reach(root, x);
            BIT.update(1, tid[t] - 1, z);
            BIT.update(ted[t] + 1, n, z);
        } else
            BIT.update(tid[x], ted[x], z);
    }
    inline long long querySubtree(int x) {
        if (x == root)
            return BIT.query(1, n);
        else if (tid[x] <= tid[root] && ted[x] >= ted[root]) {
            int t = reach(root, x);
            return BIT.query(1, tid[t] - 1) + BIT.query(ted[t] + 1, n);
        } else
            return BIT.query(tid[x], ted[x]);
    }
};
TreeChain TC;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 2; i <= n; i++) {
        int x;
        scanf("%d", &x);
        addEdge(i, x);
        addEdge(x, i);
    }
    TC.init(1);
    for (int i = 1; i <= n; i++) TC.updateInit(i, a[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        int opt, x, y, z;
        scanf("%d%d", &opt, &x);
        if (opt == 1)
            TC.changeRoot(x);
        else if (opt == 2) {
            scanf("%d%d", &y, &z);
            TC.updateRoute(x, y, z);
        } else if (opt == 3) {
            scanf("%d", &y);
            TC.updateSubtree(x, y);
        } else if (opt == 4) {
            scanf("%d", &y);
            printf("%lld\n", TC.queryRoute(x, y));
        } else {
            printf("%lld\n", TC.querySubtree(x));
        }
    }
    return 0;
}
posted @ 2019-07-31 15:20  xukl21  阅读(211)  评论(0编辑  收藏  举报