传送门
题意:给定一个带点权的树,操作1:顶点u的点权+v,u的孩子节点点权-v,u的孩子节点的孩子节点点权+v...
,操作2:查询某个点的点权
.
分析:
- 首先我们可以求出dfs序,但是这里的修改并不是普通的区间修改,而是层数奇偶性相同的顶点加,不同的顶点减 。
- 我们可以用两棵线段树分别维护奇数层顶点的修改,偶数层顶点的修改。
- 由于题目只涉及单点查询,所以我们查询的时候分别求出两棵线段树的单点值,然后根据奇偶性加减即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 2e5+10;
const int mx = 40;
const int mod = 1e9+7;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int INF = 1e9+7;
//给定带点权的树 单点修改 给顶点v点权+x的时候 其子节点点权-x 子节点的子节点点权+x 以此类推直到叶子节点
//单点查询
//由于只涉及单点查询 我们开两个数组d1 d2分别记录修改奇数顶点/偶数顶点的dfs序区间影响
struct
{
int to,next;
}e[maxn<<1];
int ecnt,head[maxn];
void add(int v,int u)
{
e[++ecnt].to=u;
e[ecnt].next=head[v];
head[v]=ecnt;
}
int dep[maxn];//dfs序的每个点的深度
int in[maxn],out[maxn],dfsclock;
void dfs(int rt,int par,int depth)//深度
{
in[rt]=++dfsclock;
dep[dfsclock]=depth;//注意不是dep[rt]=depth
for(int i=head[rt];i;i=e[i].next)
{
int to=e[i].to;
if(to == par) continue;
dfs(to,rt,depth+1);
}
out[rt]=dfsclock;
}
ll d[2][maxn<<2];//两棵线段树
ll tag[2][maxn<<2];
int n,q;
int a[maxn];//初始点权
inline int lc(int &rt) {return rt<<1;}
inline int rc(int &rt) {return rt<<1|1;}
inline void change(int rt,int l,int r,int x,int k)
{
tag[k][rt]+=x;
d[k][rt]+=(r-l+1)*x;
}
inline void pushdown(int rt,int l,int r,int k)
{
int mid=(l+r)>>1;
if(tag[k][rt])
{
change(lc(rt),l,mid,tag[k][rt],k);
change(rc(rt),mid+1,r,tag[k][rt],k);
}
tag[k][rt]=0;
}
inline void updata(int rt,int l,int r,int vl,int vr,int x,int k)
{
if(r<vl || l>vr) return ;
if(vl<=l && r<=vr)
{
change(rt,l,r,x,k);
return ;
}
int mid=(l+r)>>1;
pushdown(rt,l,r,k);
updata(lc(rt),l,mid,vl,vr,x,k);
updata(rc(rt),mid+1,r,vl,vr,x,k);
}
inline ll query(int rt,int l,int r,int indx,int k)
{
if(l == r) return d[k][rt];
int mid=(l+r)>>1;
pushdown(rt,l,r,k);
if(indx<=mid) return query(lc(rt),l,mid,indx,k);
else return query(rc(rt),mid+1,r,indx,k);
}
int main()
{
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<n;i++)
{
int v,u;
scanf("%d%d",&v,&u);
add(v,u),add(u,v);
}
dfs(1,-1,1);
while(q--)
{
int f,x;
scanf("%d %d",&f,&x);
if(f == 1)
{
int v;
scanf("%d",&v);
updata(1,1,n,in[x],out[x],v,dep[in[x]]%2);
}
else
{
ll d0=query(1,1,n,in[x],0),
d1=query(1,1,n,in[x],1);
if(dep[in[x]]%2 == 0) //偶层顶点 +d0-d1
{
printf("%lld\n",a[x]+d0-d1);
}
else printf("%lld\n",a[x]+d1-d0);
}
}
return 0;
}