P11993 [JOIST 2025] 迁移计划 / Migration Plan 题解

P11993 [JOIST 2025] 迁移计划 / Migration Plan

思路

我们先考虑暴力。发现暴力的话操作 1 复杂度是 \(O(n)\),其他两个都是 \(O(1)\),考虑平衡一下。

先将序列用 dfs 序拍平,然后考虑对每一个深度都开一个完整的线段树去维护。发现操作 1 实际上就是将给定的两个深度的线段树合并起来,操作 2 就是在线段树上单点修改,操作 3 就是在线段树上查询子树和。(只有子树内的点会恰好贡献到这里)

code

并没有细节。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+7;
namespace sgt_merge{
	int tr[N<<5],ls[N<<5],rs[N<<5],rt[N],idcnt=0;
	#define lsu ls[u]
	#define rsu rs[u]
	#define mid (l+r>>1)
	void push_up(int u){tr[u]=tr[lsu]+tr[rsu];}
	void modify(int &u,int l,int r,int x,int w){
		if(!u)u=++idcnt;
		if(l==r){tr[u]+=w;return;}
		x<=mid?modify(lsu,l,mid,x,w):modify(rsu,mid+1,r,x,w);
		push_up(u);
	}
	int query(int u,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return tr[u];
		int ans=0;
		if(ql<=mid)ans+=query(lsu,l,mid,ql,qr);if(qr>mid)ans+=query(rsu,mid+1,r,ql,qr);
		return ans;
	}
	int merge(int &x,int &y){
		if(!x||!y)return x+y;
		tr[x]+=tr[y];
		ls[x]=merge(ls[x],ls[y]),rs[x]=merge(rs[x],rs[y]);
		return x;
	}
}
using namespace sgt_merge;
int n,Q,dep[N],dfncnt=0,dfn[N],loc[N],val[N],siz[N];
vector <int> q[N];
void dfs1(int u){
	dfn[u]=++dfncnt,loc[dfncnt]=u;siz[u]=1;
	modify(rt[dep[u]],1,n,dfn[u],val[u]);
	for(int v:q[u]){
		dep[v]=dep[u]+1;dfs1(v);siz[u]+=siz[v];
	}
}
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;for(int i=2,x;i<=n;i++)cin>>x,q[x].push_back(i);
	for(int i=1;i<=n;i++)cin>>val[i];
	dfs1(1);cin>>Q;
	for(int i=1,op,x,y;i<=Q;i++){
		cin>>op;
		if(op==1){
			cin>>x>>y;rt[y]=merge(rt[y],rt[x]),rt[x]=0;
		}
		if(op==2){
			cin>>x>>y;modify(rt[dep[x]],1,n,dfn[x],y);
		}
		if(op==3){
			cin>>x;cout<<query(rt[dep[x]],1,n,dfn[x],dfn[x]+siz[x]-1)<<'\n';
		}
	}
	return 0;
}
posted @ 2025-07-19 14:28  all_for_god  阅读(15)  评论(0)    收藏  举报