题目链接:https://ac.nowcoder.com/acm/contest/392/H
作者:fzszkl
链接:https://ac.nowcoder.com/discuss/160376?type=101&order=time&pos=&page=1
来源:牛客网
首先离线操作,建出整棵树的最终状态。对这棵树进行DFS,i号点被搜到的时间记为DFNiDFNi。DFN有一个重要的性质,就是同一棵子树内的节点的DFN总是连续的,所以我们可以用一个线段树按照DFN的顺序来维护所有点的点权。
考虑到一个操作会影响到一个点有以下两个条件:1、被操作的是被影响的点的祖先(或它自己);2、加点的时间早于操作的时间。
所以我们执行修改和询问时直接对整棵子树执行,执行加点操作的时候直接将这个点当前的点权**清零**即可。这样可以消除所有早于它出现的操作的影响。因为只有单点询问,所以本题线段树可用差分树状数组代替。时间复杂度O(MlogM)O(MlogM)。
#include <bits/stdc++.h> using namespace std; #define re register #define ll long long #define fi first #define se second #define pb push_back const int maxn=1e5+10; void read(int &a) { a=0; int d=1; char ch; while(ch=getchar(),ch>'9'||ch<'0') if(ch=='-') d=-1; a=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9') a=a*10+ch-'0'; a*=d; } void write(int x) { if(x<0) putchar(45),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } struct note { int op,a,x,asd; }tmp[4*maxn]; int cnt[maxn],cnt_end[maxn],t,tree[maxn],n; vector <int> q[maxn]; void dfs(int x) { cnt[x]=++t; for(re int i=0;i<q[x].size();i++) dfs(q[x][i]); cnt_end[x]=t; } int lowbit(int k) { return k&-k; } void add(int i,int x) { while(i<=t) { tree[i]+=x; i+=lowbit(i); } } void add1(int l,int r,int x) { add(l,x); add(r+1,-x); } ll sum(int i) { ll ans=0; while(i) { ans+=tree[i]; i-=lowbit(i); } return ans; } int main() { int T; read(T); for(re int i=1;i<=T;i++) { read(tmp[i].op); read(tmp[i].a); if(tmp[i].op==1) { q[tmp[i].a].pb(++n); tmp[i].asd=n; } else if(tmp[i].op==2) read(tmp[i].x); } dfs(0); for(re int i=1;i<=T;i++) { if(tmp[i].op==1) { int val=sum(cnt[tmp[i].asd]); add1(cnt[tmp[i].asd],cnt[tmp[i].asd],-val); } else if(tmp[i].op==2) add1(cnt[tmp[i].a],cnt_end[tmp[i].a],tmp[i].x); else printf("%lld\n",sum(cnt[tmp[i].a])); } return 0; }