给定一个有根树,初始只有根节点 1 1 1。每个节点都有一个点权,初始皆为 0 0 0。
现有两种操作:
q q q 次操作后输出所有点的点权
离线处理所有操作。先将所有操作存起来,然后在最终的树上跑一遍 d f s dfs dfs,确定每个点的 d f s dfs dfs 序(即 d f n [ i ] dfn[i] dfn[i])。
有一个性质:如果以 u p [ i ] up[i] up[i] 表示以 i i i 为根的子树中最大的 d f n dfn dfn,那么所有 i i i 的子树中的节点 j j j,都满足 d f n [ i ] ≤ d f n [ j ] ≤ u p [ i ] dfn[i] \leq dfn[j] \leq up[i] dfn[i]≤dfn[j]≤up[i]
如果我们建立一颗 以 d f s dfs dfs序为下标 的线段树,那么每次操作二就等价于某个区间修改。
问题是这个区间修改会修改所有 i i i 的子树中的节点,但是可能有些节点还没有被加进来。
其实对于某个点 j j j 来说,它一定是在某个时间节点被添加进来的,在这个时间节点之前的所有区间修改都跟他没有关系,那么我们新添加一个节点时,它的点权其实可能被之前的操作二影响了,并且刚好储存在线段树对应的位置中。我们只需要单点查询一下这个点的点权是多少,然后进行一次 L = R L=R L=R 的区间修改 就可以抵消之前的影响了。
// Problem: F. A Growing Tree
// Contest: Codeforces - Codeforces Round 907 (Div. 2)
// URL: https://codeforces.com/contest/1891/problem/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;
typedef long long ll;
const int N = 500050;
std::vector<int> g[N];
int dfn[N]; //dfs序
int up[N]; //子树dfn上限
int tot; //时间戳
int pt[N]; //每个时间戳对应的点
void dfs(int u,int fa){
dfn[u] = ++tot;
pt[tot] = u;
for(auto v : g[u])
if(v != fa)
dfs(v,u);
up[u] = tot;
}
struct node{ //线段树以dfn序为下标,记录每个位置的点
int ID; //这个dfn对应的节点编号
ll val; //点权
}tree[N<<2];
void build(int p,int l,int r){
tree[p] = {0,0};
if(l == r){
tree[p].ID = pt[l];
return;
}
int mid = l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
void update(int p,int l,int r,int L,int R,ll x){ //[L,R]位置val += x
if(L <= l && r <= R){
tree[p].val += x;
return;
}
int mid = l+r>>1;
if(L <= mid) update(p<<1,l,mid,L,R,x);
if(R > mid) update(p<<1|1,mid+1,r,L,R,x);
}
ll query(int p,int l,int r,int pos,ll res){ //单点修改
res += tree[p].val;
if(l == r) return res;
int mid = l+r>>1;
if(pos <= mid) return query(p<<1,l,mid,pos,res);
else return query(p<<1|1,mid+1,r,pos,res);
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t;
std::cin>>t;
while(t--){
int q;
std::cin>>q;
int cnt = 1; //节点编号
std::vector<std::tuple<int,int,ll>> modify; //离线修改
while(q--){
int opt;
std::cin>>opt;
if(opt == 1){
int id;
std::cin>>id;
g[id].push_back(++cnt);
g[cnt].push_back(id);
modify.emplace_back(1,cnt,0);
}
else{
int id;
ll x;
std::cin>>id>>x;
modify.emplace_back(2,id,x);
}
}
dfs(1,0);
build(1,1,tot);
for(auto [type,id,x] : modify){
if(type == 1){
ll d = query(1,1,tot,dfn[id],0);
update(1,1,tot,dfn[id],dfn[id],-d);
}
else{
update(1,1,tot,dfn[id],up[id],x);
}
}
std::vector<ll> ans(cnt+1,0);
fore(i,1,cnt+1) ans[i] = query(1,1,tot,dfn[i],0);
fore(i,1,cnt+1) std::cout<<ans[i]<<" \n"[i==cnt];
tot = 0;
fore(i,1,cnt+1) g[i].clear();
}
return 0;
}