A little girl loves problems on trees very much. Here's one of them.
A tree is an undirected connected graph, not containing cycles. The degree of node x in the tree is the number of nodes y of the tree, such that each of them is connected with node x by some edge of the tree.
Let's consider a tree that consists of n nodes. We'll consider the tree's nodes indexed from 1 to n. The cosidered tree has the following property: each node except for node number 1 has the degree of at most 2.
Initially, each node of the tree contains number 0. Your task is to quickly process the requests of two types:
The first line contains integers n (2 ≤ n ≤ 105) and q (1 ≤ q ≤ 105) — the number of tree nodes and the number of requests, correspondingly.
Each of the next n - 1 lines contains two integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi), that show that there is an edge between nodes ui and vi. Each edge's description occurs in the input exactly once. It is guaranteed that the given graph is a tree that has the property that is described in the statement.
Next q lines describe the requests.
The numbers in the lines are separated by single spaces.
For each request to print the node value print an integer — the reply to the request.
3 6 1 2 1 3 0 3 1 2 0 2 3 1 0 1 5 2 1 1 1 2 1 3
9 9 6
6 11 1 2 2 5 5 4 1 6 1 3 0 3 1 3 0 3 4 5 0 2 1 4 0 1 5 5 0 4 6 2 1 1 1 2 1 3 1 4 1 5 1 6
11 17 11 16 17 11
题目大意:
有一颗具有N个点的一棵树,现在我们有两种操作:
①0 u,x,d,表示以点u为中心,距离他为d之内的所有点都增加x个单位价值。
②1 u,表示查询此时节点u的价值。
一开始所有点的点权价值都是0.
除了节点1以外,其他各个点的度都小于等于2.
思路:
①我们通过预处理Dfs序,我们可以在树上更新操作的时候,很容易把子树方向的问题搞定了。
②因为我们已知:除了节点1以外,其他各个点的度都小于等于2.那么我们不难知道,除了节点1以外,其子树的形状都是链状的。那么除了节点1以外,节点u在线段树上的的编号为L【u】的话,其儿子的编号就一定是L【u】+1,孙子的编号就一定是L【u】+2............依次类推。那么我们对于子树方向的问题就不难搞定了,根据其深度,我们可以update(L【u】,min(L【u】+d,R【u】));
③接下来考虑父亲方向和兄弟方向,我们知道,此时除了节点1以外,所有的部分都是链状的,那么如果我们对节点u的更新分成两种:
1.距离到达不了根节点1的,那么对应这种情况我们已经处理完了子树方向之后,我们再update(L【u】-d,L【u】-1)即可。
2.能够到达根节点1的,那么对应这种情况我们处理完了子树方向之后,我们还需要将从1~u节点这条链上的所有节点都加上价值,然后我们还需要将其他兄弟链进行处理。我们知道,对于Dfs序来讲,我们无法区间更新这样从节点1到各个深度为一定值的问题。那么我们考虑再预处理出来一个Bfs序。
④Dfs序很好理解,Bfs序一句话也可以讲通:根据出队的顺序我们将节点进行标号,那么对于Bfs序预处理出来的部分,我们对于深度从1到x深度的部分的所有点,都一定是连续的编号。那么对于这样一个BFS序来讲,我们就可以处理从节点1到其他各个节点深度为一定值的更新问题了。
⑤那么我们现在已经有了Bfs序,那么我们就可以处理③中叙述的遗留问题了,我们可以很容易搞定节点1到节点u之间链上区间更新的部分,那么有了Bfs序之后,也就可以处理从1到各个深度为d的点的区间更新部分了,那么整个问题也就解决了,我们知道,Dfs序和Bfs序处理出来的节点编号在树上是不同的,所以我们需要维护两颗线段树进行区间更新。
⑥过程维护的时候,注意特判一些情况,细节很多,需要深入思考。
Ac代码:
By mengxiang000, contest: Codeforces Round #169 (Div. 2), problem: (E) Little Girl and Problem on Trees, Accepted, #
#include
#include
#include
#include
using namespace std;
int n,q;
vectormp[150000];
/************************************/
struct node
{
int u,depth;
}now,nex;
int depthL[150000];
int depthR[150000];
int num[150000];
int vis[150000];
int L[150000];
int R[150000];
int dist[150000];
int cnt;
void Dfs(int u,int from,int dis)
{
L[u]=++cnt;
dist[u]=dis;
for(int i=0;is;
now.u=1;now.depth=0;
s.push(now);
memset(depthL,-1,sizeof(depthL));
memset(depthR,0,sizeof(depthR));
memset(vis,0,sizeof(vis));
vis[1]=1;
while(!s.empty())
{
tot++;
now=s.front();
num[now.u]=tot;
if(depthL[now.depth]==-1)depthL[now.depth]=num[now.u];
depthR[now.depth]=max(depthR[now.depth],num[now.u]);
s.pop();
for(int i=0;i=L&&r<=R)
{
tree[rt]+=(r-l+1)*c;
flag[rt]+=c;
return ;
}
int m=(l+r)/2;
pushdown(l,r,rt);
if(L<=m)update(L,R,c,lson);
if(R>m)update(L,R,c,rson);
pushup(rt);
}
int query(int p,int l,int r,int rt)
{
if(l==r)return tree[rt];
int m=(l+r)/2;
pushdown(l,r,rt);
if(p<=m)return query(p,lson);
if(p>m)return query(p,rson);
pushup(rt);
}
/************************************/
int sum[150000*4];
int flag2[150000*4];
void pushup2(int rt)
{
sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void pushdown2(int l,int r,int rt)
{
if(flag2[rt])
{
int m=(l+r)/2;
flag2[rt*2]+=flag2[rt];
flag2[rt*2+1]+=flag2[rt];
sum[rt*2]+=(m-l+1)*flag2[rt];
sum[rt*2+1]+=(r-(m+1)+1)*flag2[rt];
flag2[rt]=0;
}
}
void build2(int l,int r,int rt)
{
sum[rt]=flag2[rt]=0;
if(l==r)return ;
int m=(l+r)/2;
pushdown(l,r,rt);
build2(lson);build2(rson);pushup2(rt);
}
void update2(int L,int R,int c,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
sum[rt]+=(r-l+1)*c;
flag2[rt]+=c;
return ;
}
int m=(l+r)/2;
pushdown2(l,r,rt);
if(L<=m)update2(L,R,c,lson);
if(R>m)update2(L,R,c,rson);
pushup2(rt);
}
int query2(int p,int l,int r,int rt)
{
if(l==r)return sum[rt];
int m=(l+r)/2;
pushdown2(l,r,rt);
if(p<=m)return query2(p,lson);
if(p>m)return query2(p,rson);
pushup2(rt);
}
/************************************/
int main()
{
while(~scanf("%d%d",&n,&q))
{
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=n-1;i++)
{
int x,y;scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
cnt=0;
Dfs(1,-1,0);
Bfs();
build(1,n,1);
build2(1,n,1);
while(q--)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x;scanf("%d",&x);
printf("%d\n",query(L[x],1,n,1)+query2(num[x],1,n,1));
}
else
{
int u,v,d;scanf("%d%d%d",&u,&v,&d);
if(u==1)
{
if(depthR[d]!=0)
update2(1,depthR[d],v,1,n,1);
else update2(1,n,v,1,n,1);
continue;
}
update(L[u],min(L[u]+d,R[u]),v,1,n,1);
if(d