Codeforces 276E Little Girl and Problem on Trees【线段树+Bfs序+Dfs序】好题!

E. Little Girl and Problem on Trees
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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:

  • Request of form: 0 v x d. In reply to the request you should add x to all numbers that are written in the nodes that are located at the distance of at most d from node v. The distance between two nodes is the number of edges on the shortest path between them.
  • Request of form: 1 v. In reply to the request you should print the current number that is written in node v.
Input

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 ≤ nui ≠ 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 request to add has the following format: 0 v x d (1 ≤ v ≤ n1 ≤ x ≤ 1041 ≤ d < n).
  • The request to print the node value has the following format: 1 v (1 ≤ v ≤ n).

The numbers in the lines are separated by single spaces.

Output

For each request to print the node value print an integer — the reply to the request.

Examples
input
3 6
1 2
1 3
0 3 1 2
0 2 3 1
0 1 5 2
1 1
1 2
1 3
output
9
9
6
input
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
output
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












你可能感兴趣的:(搜索,思维,线段树,Codeforces,276E)