Codeforces276E:Little Girl and Problem on Trees

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 andvi.
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?≤?n, 1?≤?x?≤?104, 1?≤?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.

Sample test(s)

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

题意:一棵树只有一个顶点,然后由这个顶点引申出多条链,对于输入 0 v x d,代表把距离V节点距离在d以内的所有节点增加x,对于输入 1 v,代表查询v节点的值

思路:这道题参考别人的代码的时候,发现用到了树状数组,但是以前并没有做过树状数组,虽说能用树状数组做的题都能用线段树做,但是树状数组还是挺巧妙的,于是临时去看了一下树状数组的原理,最后结合别人的思想把这道题A了
首先我们对于一条链而言,当这个节点在链中,往下更新d的距离很好办,但是往上更新到1节点的时候,我们假设还有d的距离没有更新,如果我们一条条的去更新很容易超时,于是我们可以对于整棵树直接更新,即所有距离1为d的节点更新的状态都是一样的
使用new动态分配内存放置超内存

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
#define ls 2*i
#define rs 2*i+1
#define up(i,x,y) for(i=x;i<=y;i++)
#define down(i,x,y) for(i=x;i>=y;i--)
#define mem(a,x) memset(a,x,sizeof(a))
#define w(a) while(a)
#define LL long long
const double pi = acos(-1.0);
#define N 100005
#define mod 19999997
const int INF = 0x3f3f3f3f;
#define exp 1e-8
//v点所在链的编号,所在层数,v在链上标号,各条链长度。
int mark[N],level[N],pos[N],length[N],id,deep;
vector<int> vec[N];
struct node
{
    int *sum,n;
    void init(int len)
    {
        n = len;
        sum = new int[n+1];
        memset(sum,0,(n+1)*sizeof(int));
    }
    int query(int i)
    {
        int ans = 0;
        for(; i<=n; i+=i&-i)
            ans+=sum[i];
        return ans;
    }
    void add(int i,int x)
    {
        for(; i>0; i-=i&-i)
            sum[i]+=x;
    }
    void updata(int l,int r,int x)//更新l~r区间
    {
        add(r,x);
        add(l-1,-x);//多余的更新减去
    }
} tree,*chain;

int dfs(int step,int u,int pre)
{
    int i,n = vec[u].size(),v;
    level[u] = step+1;//层数要加上1所在的那层
    mark[u] = id;
    pos[u] = step;//在链上的标号不算1节点,所以不加1
    up(i,0,n-1)
    {
        v = vec[u][i];
        if(v == pre) continue;
        return dfs(step+1,v,u);
    }
    return step;
}

void init()
{
    int i,n=vec[1].size(),len,v;
    chain = new node[n];
    level[1]=1;
    up(i,0,n-1)//对每条链进行初始化
    {
        id = i;
        v = vec[1][i];
        len = dfs(1,v,1);
        length[i]=len;
        deep = max(len,deep);//找出最长的链的深度
        chain[i].init(len);//更新每条链的深度
    }
    tree.init(++deep);//整棵树的深度
}
int query(int v)
{
    int ans = 0;
    ans = tree.query(level[v]);
    if(v!=1)
    {
        ans+=chain[mark[v]].query(pos[v]);
    }
    return ans;
}
void updata(int v,int x,int d)
{
    int l,r;
    if(v == 1)
    {
        if(deep>=1+d) r = 1+d;//比较树深度与d的深度来确定更新深度
        else r = deep;
        tree.updata(1,r,x);
        return;
    }
    //对于每条链,r代表往下更新的深度,l代表往上更新的深度,先更新到1节点为止
    if(length[mark[v]]>=pos[v]+d) r = pos[v]+d;
    else r = length[mark[v]];
    if(1<=pos[v]-d) l = pos[v]-d;
    else l = 1;
    chain[mark[v]].updata(l,r,x);
    d-=level[v]-1;
    if(d>=0)//到了1节点还有剩下
    {
        if(deep>=1+d) r = 1+d;//以1节点为原点,更新所有链,深度为r
        else r = deep;
        tree.updata(1,r,x);
        if(r>=2)//对于要求的点,由于更新了两次,要减去这次的更新
        {
            if(length[mark[v]]>=r-1) r = r-1;
            else r = length[mark[v]];
            chain[mark[v]].updata(1,r,-x);
        }
    }
}
int main()
{
    int i,n,q,x,y;
    scanf("%d%d",&n,&q);
    up(i,1,n-1)
    {
        scanf("%d%d",&x,&y);
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    init();
    int cas,v,d;
    w(q--)
    {
        scanf("%d%d",&cas,&v);
        if(!cas)
        {
            scanf("%d%d",&x,&d);
            updata(v,x,d);
        }
        else
            printf("%d\n",query(v));
    }

    return 0;
}



				
时间: 2024-08-01 12:48:36

Codeforces276E:Little Girl and Problem on Trees的相关文章

UVA10214 Trees in a Wood. 欧拉phi函数

只看某一个象限 能看到的数 == 一个 象限*4+4 能看到的树既距离原点的距离 gcd(x,y)==1 a 和 b 一大一小 预处理2000以内的phi函数,枚举小的一条边 从1...a 与 a gcd 为 1 的数的个数就是 phi(a) 从 1+a ... 2*a  与 a gcd 为 1 的数的个数 因为 GCD(i,a) = GCD(i+a,a) 所以还是 phi(a) .... Trees in a Wood. Time Limit: 3000MS   Memory Limit: U

Java数据结构四之——二叉树的前、中、后序遍历

程序来自Program Creek 前 Preorder binary tree traversal is a classic interview problem about trees. The key to solve this problem is to understand the following: What is preorder? (parent node is processed before its children) Use Stack from Java Core lib

迪杰斯特拉的证明

[摘要]逆向思维是一种思考问题的方式,它有悖于通常人们的习惯,而正是这一特点,使得许多靠正常思维不能或是难于解决的问题迎刃而解.本文通过几个例子,总结了逆向思维在信息学解题中的应用. [关键字] 逆向思维容斥原理参数搜索 二分动态规划记忆化   [正文] 引言 我们先看一个简单的问题: 平面上有四个点,构成一个边长为1的正方形.现在进行一种操作,每次可以选择两个点A和B,把A关于B对称到C,然后把A去掉. 求证:不可能经过有限次操作得到一个边长大于1的正方形 操作后的结果是相当复杂的,如果我们从

2018.3.5-6 knapsack problem, sequence alignment and optimal binary search trees

这周继续dynamic programming,这三个算法都是dynamic programming的. knapsack problem有一种greedy的解法,虽然简单但是不保证正确,这里光头哥讲的是dynamic的解法.其实和上次那个max weight independent set的算法差不多,同样是每个物件都判断一遍有这个物件和没这个物件两种情况,用bottom-up的方法来解,然后得到一个最大的value值,这时因为没有得到具体的选择方案,所以最后还需要一部重构的步骤得到具体方案.

[LeetCode&amp;Python] Problem 617. Merge Two Binary Trees

Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then

【计算几何】【预处理】【枚举】Urozero Autumn Training Camp 2016 Day 5: NWERC-2016 Problem K. Kiwi Trees

发现由于角的度数和边的长度有限制,那俩圆如果放得下的话,必然是塞在两个角里. 于是预处理n个圆心的位置(注意要判断那个圆会不会和其他的边界相交),然后n^2枚举俩角即可. #include<cstdio> #include<cmath> using namespace std; #define EPS 0.00000001 struct Point{ double x,y; double length(){ return sqrt(x*x+y*y); } }a[2010]; typ

HDU1294 Rooted Trees Problem(整数划分 组合数学 DP)

讲解见http://www.cnblogs.com/IMGavin/p/5621370.html, 4 可重组合 dfs枚举子树的节点个数,相乘再累加 1 #include<iostream>  2 #include<cstdio>  3 #include<cstring>  4 #include<cstdlib>  5 #include<algorithm>  6 using namespace std;  7 typedef long lon

HDOJ 4010 Query on The Trees LCT

LCT: 分割.合并子树,路径上全部点的点权添加一个值,查询路径上点权的最大值 Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2582    Accepted Submission(s): 1208 Problem Description We have met so many problems

[leetcode-95-Unique Binary Search Trees II]

Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n. For example,Given n = 3, your program should return all 5 unique BST's shown below. 1 3 3 2 1 \ / / / \ 3 2 1 1 3 2 / / \ 2 1 2 3 思路: This probl