题意:对树上两点区间增加或减少每点的权值,单点查询每点的权值。
思路:一开始线段树写的,但是我的被卡了2*maxn的空间,优化一下就可以了,但是嫌太麻烦,出题人可能就打算卡部分人的线段树。
用bit的话,类似预处理数组,每次查询0-x点的区间和就可以,修改左端点和右端点的权值为v和-v即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn = 5e4+5;
int n,m,id,q,top[maxn],a[maxn],p[maxn],par[maxn],son[maxn],sz[maxn],deep[maxn];
vector<int>e[maxn];
struct BIT{
int node[maxn];
int lb(int x){return x&(-x);}
void init(){forn(i,maxn)node[i] = 0;}
void update(int pos,int v){for(int i = pos;i<=n;i+=lb(i))node[i]+=v;}
int ask(int pos){int sum = 0;for(int i = pos;i;i-=lb(i))sum+=node[i];return sum;}
}bit;
void init(){
forn(i,maxn){
son[i] = 0;
e[i].clear();
}
bit.init();
id = 0;
}
void dfs(int u,int pre,int d){
sz[u] = 1,par[u] = pre,deep[u] = d;
for(auto v:e[u])if(v!=pre){
dfs(v,u,d+1);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u] = v;
}
}
void getpos(int u,int gg){
top[u] = gg,p[u] = ++id;
if(son[u]) getpos(son[u],gg);
for(auto v:e[u])if(v!=par[u]&&v!=son[u]){
getpos(v,v);
}
}
void change(int x,int y,int v){
int fx = top[x],fy = top[y];
while(fx!=fy){
if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
bit.update(p[fx],v);
bit.update(p[x]+1,-v);
x = par[fx],fx = top[x];
}
if(deep[x]>deep[y]) swap(x,y);
//cerr<<x<<' '<<p[x]<<' '<<v<<'
';
bit.update(p[x],v);
bit.update(p[y]+1,-v);
}
int main(){
IO;
while(cin>>n>>m>>q){
init();
for1(i,n) cin>>a[i];
forn(i,m){
int x,y;cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,0,0);
getpos(1,1);
for1(i,n){
bit.update(p[i],a[i]);
bit.update(p[i]+1,-a[i]);
}
while(q--){
char c;cin>>c;
if(c=='Q'){
int x;cin>>x;
cout<<bit.ask(p[x])<<'
';
}else{
int x,y,z;cin>>x>>y>>z;
if(c=='D') z = -z;
change(x,y,z);
}
}
}
return 0;
}