第一行一个正整数M,接下来M行,每行先输入一个正整数O表示操作类型,再输入一个非负整数i表示操作或询问的节点编号,如果O=2,再输入一个正整数a。
对于每个询问3,输出一个非负整数表示询问的答案。示例1
9 1 0 2 0 1 3 0 3 1 1 0 1 1 2 0 2 3 1 3 3
1 1 3 2
1≤M≤4×1051\le M\le 4\times 10^51≤M≤4×105,保证操作1的数量不超过10510^5105,保证操作2中的参数a满足1≤a≤9991\le a\le 9991≤a≤999
题意:
操作1:给节点 i 新加一个节点,编号为总结点数
操作2:给节点 i 和它的子树上的每一个节点 增加一个权值 w
操作3:查询节点 i 的权值
操作2 + 操作3 可以用 dfs序 + 树状数组来解决
操作1,考虑离线操作,将所有节点保存下来,最后再跑dfs序
当枚举到操作 1 的时候,给这个点的编号位置加上这个点刚加过的权值,最后查询的时候把这个权值删除就可以了
//-------------------------代码---------------------------- //#define int ll const int N = 4e5+10; int n,m; V<int> e[N]; int l[N],r[N],num,op[N],pos[N],a[N],w[N]; void dfs(int u,int fa) { l[u] = ++ num; for(auto it:e[u]) { if(it == fa) continue; dfs(it,u); } r[u] = num; } int tr[N<<2]; void add(int x,int v) { for(int i = x;i<=num + 1;i += lowbit(i) ) tr[i] += v; } int sum(int x) { int res = 0;for(int i = x;i;i-=lowbit(i)) res += tr[i];return res; } void solve() { // cin>>n>>m; cin>>m; int cnt = 0; fo(i,1,m) { cin>>op[i];cin>>pos[i]; if(op[i] == 2) cin>>a[i]; else if(op[i] == 1) { e[pos[i]].pb(++cnt); e[cnt].pb(pos[i]); a[i] = cnt; } } dfs(0, -1); ms(tr,0); fo(i,1,m) { if(op[i] == 1) { w[l[a[i]]] = sum(l[a[i]]); } else if(op[i] == 2) { add(l[pos[i]],a[i]); add(r[pos[i]] + 1,-a[i]); } else { int ans = sum(l[pos[i]]) - w[l[pos[i]]]; cout<<ans<<endl; } } } void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------