题意:
思路:
离线操作,把所有操作存起来,对于所有1操作建好一颗最终的树就变成了裸的树链剖分
但是可能会出现,一个点还没建出来就已经被加了权值的错误
因此对于每一个操作1就将新建的点的权值归零
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int M = 4e5 + 10;
const int N = 1e5 + 10;
struct OP{
int type,u,dx;
}op[M];
vector<int> G[N];
ll w[N];//初始权值
int dep[N],fa[N];//深度,父亲
int son[N],sz[N],id[N],dfn[N],tt;//重儿子,子树大小,i的dfn,dfn是i的编号,dfn
int top[N];//链头
//线段树部分
struct Node{
int l,r;
ll sum,lazy;
}tr[N<<2];
void pushup(int p){
tr[p].sum = tr[p<<1].sum +tr[p<<1|1].sum;
}
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
if(l == r){
tr[p].sum = w[id[l]];
return;
}
int mid = l + r >> 1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void pushdown(int p){
ll lazy = tr[p].lazy;
if(lazy){
tr[p<<1].lazy += lazy;
tr[p<<1|1].lazy += lazy;
tr[p<<1].sum += (tr[p<<1].r - tr[p<<1].l + 1)*lazy;
tr[p<<1|1].sum += (tr[p<<1|1].r - tr[p<<1|1].l + 1)*lazy;
tr[p].lazy = 0;
}
}
void update(int p,int L,int R,ll dx){
int l = tr[p].l,r = tr[p].r;
if(l >= L&&r <= R){
tr[p].lazy += dx;
tr[p].sum += (r - l + 1)*dx;
return;
}
pushdown(p);
int mid = l + r >> 1;
if(L <= mid) update(p<<1,L,R,dx);
if(R > mid) update(p<<1|1,L,R,dx);
pushup(p);
}
ll query(int p,int L,int R){
int l = tr[p].l,r = tr[p].r;
if(L <= l&&R >= r) return tr[p].sum;
pushdown(p);
int mid = l + r >> 1;
ll ans = 0;
if(L <= mid) ans += query(p<<1,L,R);
if(R > mid) ans += query(p<<1|1,L,R);
return ans;
}
//线段树部分
void dfs1(int u){
sz[u] = 1;
for(int i = 0;i < G[u].size();i++){
int v = G[u][i];
if(v == fa[u]) continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs1(v);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]){
son[u] = v;
}
}
}
//x为当前重链的链头
void dfs2(int u,int x){
dfn[u] = ++tt;
id[tt] = u;
top[u] = x;
if(!son[u]) return;
dfs2(son[u],x);
for(int i = 0;i < G[u].size();i++){
int v = G[u][i];
if(v == fa[u] || v == son[u]) continue;
dfs2(v,v);
}
}
void updateTree(int p,ll dx){
update(1,dfn[p],dfn[p] + sz[p] - 1,dx);
}
void updateOne(int p,ll dx){
update(1,dfn[p],dfn[p],dx);
}
ll qPath(int u,int v){
ll ans = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[v]) swap(u,v);
ans = (ans + query(1,dfn[top[u]],dfn[u]));
u = fa[top[u]];
}
if(dep[u] < dep[v]) swap(u,v);
ans = ans + query(1,dfn[v],dfn[u]);
return ans;
}
int main(){
int m;scanf("%d",&m);
int idx = 0;
int cnt = 0;//现在树的大小 - 1
for(int i = 1,opt,u,dx;i <= m;i++){
scanf("%d",&opt);
if(opt == 1){
scanf("%d",&u);
u++;
G[u].push_back(++cnt + 1);
G[cnt + 1].push_back(u);
op[++idx].type = 1;
op[idx].u = cnt + 1;
}else if(opt == 2){
//存下修改
op[++idx].type = 2;
scanf("%d%d",&op[idx].u,&op[idx].dx);
op[idx].u++;
}else{
//存下询问
op[++idx].type = 3;
scanf("%d",&op[idx].u);
op[idx].u++;
}
}
int n = cnt + 1;
dfs1(1);
dfs2(1,-1);
build(1,1,n);
for(int i = 1;i <= idx;i++){
if(op[i].type == 1){
updateOne(op[i].u,-qPath(op[i].u,op[i].u));
}else if(op[i].type == 2){
updateTree(op[i].u,op[i].dx);
}else{
printf("%lld\n",qPath(op[i].u,op[i].u));
}
}
return 0;
}

京公网安备 11010502036488号