给一棵树,有20w个结点,每一个节点有一个初值,接下来有20w个询问,支持两种操作,一种是对某个节点+x,然后对子节点-x,再对孩子节点的子节点+x...,另外一种操作是查询某个节点的值。
如果用朴素的做法,查询是o(1)的,但是更新的操作是o(n)的,这样显然是不行的。
更新是对奇数层和偶数层节点进行更新,接下来神奇地运用了dfs序,对整个树进行dfs,并对点标上时间戳,更新一个节点就要对整个子树进行更新,对于一棵子树来说,节点的时间戳是连续的,对于连续的区间更新,我们就可以利用线段树了。
这里要用两棵线段树,分别维护奇数层和偶数层。更新的复杂度o(logn),查询操作o(logn),总共是o(mlogn),就可以了。
写了两道线段树的题,感觉自己写的特别丑..不过看了大神的代码也涨了很多姿势...
pq说HH的线段树不是很好...可能是因为我太渣,感觉差不多,理解起来也挺顺畅的
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = (int)2e5+10;
#define ls rt << 1
#define rs rt << 1 | 1
#define lson l , m , ls
#define rson m+1 , r , rs
vector<int> G[maxn];
int val[maxn];//存点的值
int idx;
int dep[maxn];//深度
int le[maxn],ri[maxn];//时间戳
typedef struct {
int x;
int val;
int num;
}seg;
seg Tree1[maxn<<3],Tree2[maxn<<3];
void build(seg T[],int l,int r,int rt){
if(l == r){
T[rt].x=0;
T[rt].val=0;
return ;
}
int m= (l+r) >> 1;
build(T,lson);
build(T,rson);
}
int query(seg T[],int p,int l,int r,int rt){//p是点在数组中的位置
if(l==r&&l==p){
if(T[rt].x){//如果该点需要更新
T[rt].val+=T[rt].x;
T[rt].x=0;
}
return T[rt].val;
}
if(T[rt].x){//如果该节点的子节点需要更新
T[ls].x+=T[rt].x;
T[rs].x+=T[rt].x;
T[rt].x=0;//重置
}
int m = (l+r) >> 1;
if(p<=m){
return query(T,p,lson);
}
else{
return query(T,p,rson);
}
}
void update(seg T[],int x,int L,int R,int l,int r,int rt){
if(L>R) return ;
if(L<=l&&R>=r){
T[rt].x+=x;
return ;
}
if(T[rt].x){//如果该节点的子节点需要更新
T[ls].x+=T[rt].x;
T[rs].x+=T[rt].x;
T[rt].x=0;
}
int m = (l+r) >> 1;
if(R<=m) update(T,x,L,R,lson);
else if(L> m) update(T,x,L,R,rson);
else{
update(T,x,L,R,lson);
update(T,x,L,R,rson);
}
}
void dfs(int x,int fa,int k){
le[x] = ++idx;
dep[x]=k;
for(int i=0;i<G[x].size();i++){
int u=G[x][i];
if(u!=fa) dfs(u,x,k^1);//找子节点共有多少
}
ri[x]=idx;
}
int main()
{
int n,m,u,v,op,Val,x,L,R,ans;
cin>>n>>m;
idx=0;
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,-1,0);
build(Tree1,1,idx,1);
build(Tree2,1,idx,1);
for(int j=0;j<m;j++){
scanf("%d",&op);
if(op==1){
scanf("%d%d",&x,&Val);
if(dep[x]){
update(Tree1,Val,le[x],ri[x],1,idx,1);
update(Tree2,-Val,le[x],ri[x],1,idx,1);
}
else{
update(Tree1,-Val,le[x],ri[x],1,idx,1);
update(Tree2,Val,le[x],ri[x],1,idx,1);
}
}
else{
scanf("%d",&x);
if(dep[x]) ans=query(Tree1,le[x],1,idx,1)+val[x];
else ans=query(Tree2,le[x],1,idx,1)+val[x];
printf("%d\n",ans);
}
}
return 0;
}