问题概述:一颗树有n个结点,编号为1到n,其中1为根节点,现有两种操作:1 x y表示将x结点的权值加上y,2 x表
示查询x到根节点中所有结点的权值和,每个结点权值初始都为0,n和m都小于50000
(http://acm.zzuli.edu.cn/zzuliacm/problem.php?cid=1159&pid=2)
输入样例: 对应输出:
1 0
5 5 3
1 2 2
1 3
3 4
3 5
2 5
1 1 2
1 3 1
2 4
2 1
解题步骤:
①对该树从根节点开始搜索,初始化step==0,每当循环到一个点k时,记录s[k].down==++step,当循环完该点及其
所有子节点准备回溯时,记录s[k].up==++step,那么树对应的区间a[s[k].down]存的便是k点权值的负数,a[s[k].up]
存的便是k点的权值
②对于树的单节点修改--即修改区间中a[s[k].down]和a[s[k].up]的值,
对于树的查询--即查询a[s[k].up]到a[2*n]中间所有值之和
③对于②操作用线段树或树状数组即可
例如对于n==5的树:1->2,1->3,3->4,3->5,第n个点的权值为n,
转化为区间就是:-1 -2 2 -3 -4 4 -5 5 3 1
#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
typedef struct
{
int up;
int down;
}Loct;
Loct s[50005];
int n, step;
long long in[100005];
vector<int> v[50005];
void Sech(int x, int p);
int lowbit(int k)
{
return k&-k;
}
void Update(int k, int y)
{
while(k<=2*n)
{
in[k] += y;
k += lowbit(k);
}
}
long long Query(int k)
{
long long sum;
sum = 0;
while(k>=1)
{
sum += in[k];
k -= lowbit(k);
}
return sum;
}
int main(void)
{
int T, m, i, a, b, t;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
step = 0;
memset(in, 0, sizeof(in));
for(i=1;i<=n;i++)
v[i].clear();
for(i=1;i<=n-1;i++)
{
scanf("%d%d", &a, &b);
v[a].push_back(b), v[b].push_back(a);
}
Sech(1, 0);
for(i=1;i<=m;i++)
{
scanf("%d", &t);
if(t==1)
{
scanf("%d%d", &a, &b);
Update(s[a].down, -b);
Update(s[a].up, b);
}
if(t==2)
{
scanf("%d", &a);
printf("%lld\n", Query(n*2)-Query(s[a].up-1));
}
}
}
return 0;
}
void Sech(int x, int p)
{
int i, temp;
s[x].down = ++step;
for(i=0;i<v[x].size();i++)
{
temp = v[x][i];
if(temp==p)
continue;
Sech(temp, x);
}
s[x].up = ++step;
}