Codeforces276E:Little Girl and Problem on Trees,catsontrees
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 ≤ n, ui ≠ 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 61 21 30 3 1 20 2 3 10 1 5 21 11 21 3
output
996
input
6 111 22 55 41 61 30 3 1 30 3 4 50 2 1 40 1 5 50 4 6 21 11 21 31 41 51 6
output
111711161711
題意:一棵樹只有一個頂點,然後由這個頂點引申出多條鏈,對於輸入 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 longconst double pi = acos(-1.0);#define N 100005#define mod 19999997const 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;}