题意:给你一颗以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]);
}

  

Codeforces 1076E Vasya and a Tree(树状数组)或dfs的更多相关文章

  1. hdu4605 树状数组+离散化+dfs

    Magic Ball Game Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  2. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  3. BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)

    题目大意: Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  4. codeforces 1076E Vasya and a Tree 【dfs+树状数组】

    题目:戳这里 题意:给定有n个点的一棵树,顶点1为根.m次操作,每次都把以v为根,深度dep以内的子树中所有的顶点(包括v本身)加x.求出最后每个点的值为多少. 解题思路:考虑到每次都只对点及其子树操 ...

  5. CodeForces - 396C On Changing Tree(树状数组)

    题目大意 给定一棵以1为根的树,初始时所有点为0 给出树的方式是从节点2开始给出每一个点的父亲 然后是 $m$ 次操作,分为两种 $1 v,k,x$ 表示在以v为根的子树中的每一个点上添加 $x-i* ...

  6. Codeforces 216D Spider&#39;s Web 树状数组+模拟

    题目链接:http://codeforces.com/problemset/problem/216/D 题意: 对于一个梯形区域,假设梯形左边的点数!=梯形右边的点数,那么这个梯形为红色.否则为绿色, ...

  7. CodeForces - 369E Valera and Queries(树状数组)

    CodeForces - 369E Valera and Queries 题目大意:给出n个线段(线段的左端点和右端点坐标)和m个查询,每个查询有cnt个点,要求给出有多少条线段包含至少其中一个点. ...

  8. HDU3333 Turing Tree 树状数组+离线处理

    Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. POJ 3321 Apple Tree(树状数组)

                                                              Apple Tree Time Limit: 2000MS   Memory Lim ...

随机推荐

  1. python中的数据类型和常用运算符

    一. python中常见的数据类型 1. 整数:任何时候运算都是精确的 2. 浮点数:运算的时候,可能会有四舍五入 3. 字符串:字符串是以单引号'或双引号"括起来的任意文本 1) 同类型的 ...

  2. hdu 1847 Good Luck in CET-4 Everybody!(sg)

    Good Luck in CET-4 Everybody! Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  3. Tomcat翻译--JNDI Resources HOW-TO

    原文:http://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html Introduction(介绍) Tomcat provide ...

  4. 使用eclipse逆向工程开发hibernate项目

    在项目设计时,要么根据需求分析建立实体类,然后正向生成数据库表:要么先进行数据库表设计,然后逆向生成实体类.也就是说,不会完成一方的设计后再花时间去匹配建立另一方,这么做的原因是: 1.如果不使用正向 ...

  5. Hibernate Validator验证框架中@NotEmpty、@NotBlank、@NotNull 的区别

    Hibernate Validator验证框架中@NotEmpty.@NotBlank.@NotNull的主要使用情况 @NotEmpty  用在集合类上面 @NotBlank   用在String上 ...

  6. Microsoft Visual Studio 2012 Update 4 RC 3 离线安装程序

    Microsoft Visual Studio 2012 Update 4 RC 3 离线安装程序 ☆ 微软官网地址:☆ http://www.microsoft.com/en-us/download ...

  7. QQ帐户的申请与登陆(25 分)

    实现QQ新帐户申请和老帐户登陆的简化版功能.最大挑战是:据说现在的QQ号码已经有10位数了. 输入格式: 输入首先给出一个正整数N(≤),随后给出N行指令.每行指令的格式为:“命令符(空格)QQ号码( ...

  8. python的编解码问题

    http://blog.chinaunix.net/uid-27838438-id-4227131.html

  9. shell 实现闰年的判断

    #!/bin/shecho "please input the year"read year let "n1=$year % 4"let "n2=$y ...

  10. TCP之半关闭与CLOSE_WAIT

    终止一个连接要经过4次握手.这由TCP的半关闭(half-close)造成的.既然一个TCP连接是全双工(即数据在两个方向上能同时传递,可理解为两个方向相反的独立通道),因此每个方向必须单独地进行关闭 ...