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;
}

浙公网安备 33010602011771号