Codeforces 1076E Vasya and a Tree(树状数组)或dfs
题意:给你一颗以1为根节点的树,初始所有节点的权值为0,然后有m个操作,每个操作将点x的所有距离不超过d的节点权值+1,问经过m次操作后每个节点权值是多少?
思路:如果是一个序列,就可以直接用树状数组做,但这是一颗树,所以我们可以想办法把它转化成序列。我们可以先求出每个节点的dfs序,以及深度和子树的大小,顺便记录每个深度都有哪些节点,子树的大小用来确认以该节点为根的子树在dfs序中的范围,此时便可用树状数组维护了。之后,我们把每个操作按能影响到的深度从大到小排序,即优先处理影响深度大的操作。设当前计算的深度为now,假设所有操的作影响的深度大于now的操作已经计算。如果当前操作影响的深度小于now,说明所有能影响到now深度的操作已经全部操作完了,此时把所有深度为now的节点权值计算出来。每读取一个操作的信息,就把操作产生的影响用树状数组维护,因为影响now深度的节点权值已经计算完毕了,所以我把以该操作的操作节点为根的子树全部加上操作的值 对之前已经计算的答案没有影响。操作全部完成后,深度从深到浅计算答案即可。
代码:
#include<bits/stdc++.h> #define LL long long #define lowbit(x) (x&(-(x))) using namespace std; const int maxn=300010; int deep[maxn],head[maxn],Next[maxn*2],ver[maxn*2],tot,cnt; int sum[maxn],sz[maxn],dfsn[maxn],mx,n; LL c[maxn],ans[maxn]; struct op{ int x,d; LL num; bool operator <(const op& rhs)const{ return (deep[x]+d)>(deep[rhs.x]+rhs.d); } }OP[maxn]; void adde(int x,int y){ ver[++tot]=y; Next[tot]=head[x]; head[x]=tot; } vector<int>re[maxn]; int get_deep(int x,int dep){ deep[x]=dep; dfsn[x]=++cnt; sz[x]=1; mx=max(mx,dep); re[dep].push_back(x); for(int i=head[x];i;i=Next[i]){ int y=ver[i]; if(!deep[y]){ get_deep(y,dep+1); sz[x]+=sz[y]; } } } LL ask(int x){ LL ans=0; for(;x;x-=lowbit(x))ans+=c[x]; return ans; } void add(int x,LL y){ for(;x<=n;x+=lowbit(x))c[x]+=y; } int main(){ int m; scanf("%d",&n); for(int i=1;i<n;i++){ int a,b; scanf("%d%d",&a,&b); adde(a,b); adde(b,a); } get_deep(1,1); scanf("%d",&m); for(int i=1;i<=m;i++){ int a,b; LL c; scanf("%d%d%lld",&a,&b,&c); OP[i]=(op){a,b,c}; } sort(OP+1,OP+1+m); int now=mx; for(int i=1;i<=m;i++){ int tmp=deep[OP[i].x]+OP[i].d; while(now>tmp){ for(int j=0;j<re[now].size();j++){ int x=re[now][j]; ans[x]=ask(dfsn[x]); } now--; } add(dfsn[OP[i].x],OP[i].num); add(dfsn[OP[i].x]+sz[OP[i].x],-OP[i].num); } while(now){ while(now){ for(int j=0;j<re[now].size();j++){ int x=re[now][j]; ans[x]=ask(dfsn[x]); } now--; } } for(int i=1;i<=n;i++) printf("%lld ",ans[i]); }
还有一种只用dfs的做法,dfs时,记录一下以该节点为起点的所有操作影响的深度范围(类似前缀和的方式),在从该节点回溯时再把影响减去,因为dfs时只会在子树中遍历,所以用这种方法就把影响限制在了子树的规定深度中。
代码:
#include<bits/stdc++.h> #define fi first #define se second #define mk make_pair #define pb push_back #define LL long long using namespace std; const int maxn=300010; int deep[maxn],head[maxn],Next[maxn*2],ver[maxn*2],tot,cnt; int now[maxn]; LL ans[maxn]; int n,m; vector< pair<int,LL> >re[maxn]; void add(int x,int y){ ver[++tot]=y; Next[tot]=head[x]; head[x]=tot; } void dfs(int x,LL val){ val+=now[deep[x]]; for(int i=0;i<re[x].size();i++){ int dep=deep[x]+re[x][i].fi; dep=min(dep,n); now[dep+1]-=re[x][i].se; val+=re[x][i].se; } ans[x]=val; for(int i=head[x];i;i=Next[i]){ int y=ver[i]; if(!deep[y]){ deep[y]=deep[x]+1; dfs(y,val); } } for(int i=0;i<re[x].size();i++){ int dep=deep[x]+re[x][i].fi; dep=min(dep,n); now[dep+1]+=re[x][i].se; } } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } scanf("%d",&m); for(int i=1;i<=m;i++){ int x,y; LL z; scanf("%d%d%lld",&x,&y,&z); re[x].pb(mk(y,z)); } deep[1]=1; dfs(1,0); for(int i=1;i<=n;i++) printf("%lld ",ans[i]); }