E. Little Girl and Problem on Trees 树状数组 + 线段树

本文深入探讨了一种特殊类型的树形结构及其操作算法,包括节点修改与查询功能,详细解析了每一步操作的原理与实现过程。
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 uiand 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.

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

好噁心的题啊。。。

each node except for node number 1 has the degree of at most 2 ... 真是好性质。..

一定要利用好这个的性质。。

然后。。 

它只有根是有多个节点的。  也就是说除了根都是直链。。 每段直链开始用连续的序号标记, 成 2----K, 每段都这样处理

然后对这样产生的序号, build 出线段树, 更新某个点周围 d 距离, 就对应到每段直链的序号中进行update

update的时候。。如果发现d 到达了 根节点, 就在利用树状数组进行维护。 如果更新距离为d ,那么就是加在  deep - d + 1 的val上面。。


#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iostream>
#include <cstring>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 211111;
#define LL long long
LL sum[N<<2|1];
LL cov[N<<2];
vector<int> vec[N];
int ra[N] , idx[N] , id_nn , top[N], fa[N] ,bottom[N];
int max_deep = 0;
int make_tree(int u,int Fa,int Top){
	idx[u] = ++id_nn; 
	ra[id_nn] = u;
	fa[u] = Fa;
	top[u] = Top;
	for(int i = 0;i < vec[u].size();i++){
		int v = vec[u][i];
		if(v!=Fa){
			bottom[u] = make_tree(v,u,Top);
		}
	}
	if(vec[u].size() <= 1){
		return bottom[u]=u;
	}
	return bottom[u];
}
#define lowbit(x) ((x)&(-x))
LL dsum[N];
void qsum_update(int pos,LL val){
	for( ; pos <= max_deep ; pos+=lowbit(pos)){
		dsum[pos] += val;
	}
}
LL getSum(int pos){
	LL ret = 0;
	//printf("sum pos=%d : ",pos);
	for(; pos > 0 ; pos -= lowbit(pos))
		ret += dsum[pos];
	return ret;
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bass 1,id_nn,1
void push_down(int l,int r,int rt){
	if(cov[rt]!=0){
		sum[rt<<1] += (r-l+1 - (r-l+1)/2) * cov[rt];
		sum[rt<<1|1] += (r-l+1)/2 * cov[rt];
		cov[rt<<1] += cov[rt];
		cov[rt<<1|1] += cov[rt];
		cov[rt] = 0;
	}
}
void push_up(int rt){
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
int ql,qr,val;
void update(int l,int r,int rt){
	if(ql<=l && r <= qr){
		sum[rt] += (r-l+1) * val;
		cov[rt] += val;
		return;
	}
	push_down(l,r,rt);
	int mid = (l+r)>>1;
	if(ql <= mid)update(lson);
	if(qr > mid)update(rson);
	push_up(rt);
}
LL query(int l,int r,int rt){

	push_down(l,r,rt);
	if(l==r){
		return sum[rt];
	}
	LL ans = 0;
	int mid = (l+r)>>1;
	if(ql <= mid) ans += query(lson);
	if(qr > mid) ans += query(rson);
	push_up(rt);
	return ans;
}
void UPDATE_tree(int d){
	ql=qr=1;
	update(bass);
	d--;
	if(d==0)return;
	//printf("zz d=%d val=%d\n",d,val);
	d = min(d,max_deep);
	d = max_deep - d + 1;
	qsum_update(d,val);
}
void UPDATE(int v,int x,int d){
	val = x;
	if(v==1){
		UPDATE_tree(d+1);
	}else{
		int idv = idx[v];
		int idtopv = idx[top[v]];
		int beggg,enddd;
		if(idv - idtopv < d){
			int dd = d - (idv-idtopv);
			beggg = idtopv + dd  - 1;
			UPDATE_tree(dd);
		}else{
			beggg = idv - d;
		}
		enddd = min(idv + d , idx[bottom[v]]);
		ql = beggg, qr = enddd;
		if(ql<=qr)
			update(bass);
	}
}
LL QUERY(int u){
	ql = qr = idx[u];
	LL ans =  query(bass);
	
	if(u!=1){
		int pos = idx[u] - idx[top[u]] + 1;
		pos = max_deep - pos + 1;
		ans += getSum(pos);
	}
	return ans;
}
int main(){	
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF){
		for(int i=1;i<=n;i++) vec[i].clear();
		for(int i = 1,u,v;i < n;i++){
			scanf("%d %d",&u,&v);
			vec[u].push_back(v);
			vec[v].push_back(u);
		}
		id_nn = 0;
		ra[1]=idx[1]=++id_nn;
		for(int i = 0;i < vec[1].size();i++){
			make_tree(vec[1][i], 1, vec[1][i] );
			max_deep = max(max_deep, idx[bottom[vec[1][i]]] - idx[vec[1][i]] +1 );
		}
		memset(dsum,0,sizeof(dsum));
		memset(sum,0,sizeof(sum));
		memset(cov,0,sizeof(cov));
		
		for(int u,v,x,d; m--; ){
			scanf("%d %d",&u,&v);
			if(u==0){
				scanf("%d %d",&x,&d);
				UPDATE(v,x,d);
			}else{
				cout << QUERY(v) << endl;
			}

		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值