#include<cstdio>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<math.h>
#include<climits>
#include<set>
#include<sstream>
#include<time.h>
#include<iomanip>
#define debug(x) cout <<#x<<" = "<<x<<endl
#define debug2(x, y) cout<<#x<<" = "<<x<<", "<<#y<<" = "<<y<<endl
#define gg cout <<"---------------QAQ---------------"<<endl
#define fi first
#define SZ(x) (int)x.size()
#define se second
#define pb push_back
#define MEM(a) memset(a, 0, sizeof(a))
#define inf 1e6
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define PI cos(-1)
#define endl "\n"
#define eps 1e-8
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
template<class T> inline void read(T &x){
x=0; char c=getchar(); int f=1;
while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;
}
const int N = 2e5+10, maxn = 1e6+10;
//void FAST(){ios::sync_with_stdio(false);cin.tie(nullptr); cout.tie(nullptr);}
const ll mod = 1e9+7;
int n, m, k;
vector<int> e[N];
int siz[N], deep[N], fa[N], wson[N];
int dfn[N], top[N], pre[N], cnt = 0;
ll lazy[N<<2], sum[N<<2], ori[N];
void dfs1(int u, int father)
{
siz[u] = 1;
for(auto v:e[u]) {
if(v == father) continue;
deep[v] = deep[u]+1; ///儿子的深度是父亲的深度加一
fa[v] = u; /// v的父节点是u
dfs1(v, u); /// 遍历儿子节点
siz[u] += siz[v]; ///儿子节点贡献的子树大小
if(siz[v] > siz[wson[u]]) ///发现更重的儿子,更新
wson[u] = v;
}
}
void dfs2(int u, int tp) ///u节点,及其所在链的链头tp
{
dfn[u] = ++cnt; ///当前节点的新编号,也就是dfs序的编号
pre[cnt] = u; ///老编号
top[u] = tp; ///链头
if(wson[u]) ///有重儿子,一定先访问重儿子
dfs2(wson[u], tp); ///访问节点,此时重儿子一定再重链,所以还是tp
for(auto v:e[u]) ///访问所有的轻儿子
{
if(v==wson[u]||v==fa[u])///轻儿子节点不能是重儿子,也不能是父亲节点
continue;
dfs2(v, v); ///每一个轻儿子,他的链头都是自己
}
}
void Push_up(int rt)
{
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void Push_down(int rt, ll m)
{
if(lazy[rt])
{
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt]*(m-(m>>1));
sum[rt<<1|1] += lazy[rt]*(m>>1);
lazy[rt] = 0;
}
}
void build(int l = 1, int r = n, int rt = 1)
{
if(l == r) {
sum[rt] = ori[pre[l]];
return ;
}
int m = (l+r)>>1;
build(lson);
build(rson);
Push_up(rt);
}
void update(int L, int R, int c, int l = 1, int r = n, int rt = 1)
{
if(L<=l&&R>=r) {
lazy[rt] += c;
sum[rt] += (ll)c*(r-l+1);
return ;
}
Push_down(rt, r-l+1);
int m = (l+r)>>1;
if(L <= m) update(L, R, c, lson);
if(R > m) update(L, R, c, rson);
Push_up(rt);
}
ll query(int L, int R, int l = 1, int r = n, int rt = 1)
{
if(L<=l&&R>=r) return sum[rt];
Push_down(rt, r-l+1);
ll ans = 0;
int m = (l+r)>>1;
if(L<=m) ans += query(L, R, lson);
if(R > m) ans += query(L, R, rson);
return ans;
}
void Update_sum(int a, int b, int c)
{
while(top[a]!=top[b])
{
if(deep[top[a]] < deep[top[b]])
swap(a, b);
update(dfn[top[a]], dfn[a], c);
a = fa[top[a]];
}
if(dfn[a] > dfn[b]) swap(a, b);
update(dfn[a], dfn[b], c);
}
ll Query_sum(int a, int b)
{
ll ans = 0;
while(top[a]!=top[b]) { ///a和b不在一条重链上
if(deep[top[a]] < deep[top[b]]) ///默认a是在下面
swap(a, b);
ans += query(dfn[top[a]], dfn[a]);
///访问这条重链,dfs[top[a]]是链头,dfn[a]是当前节点编号
a = fa[top[a]]; ///往上面访问
}
if(dfn[a] > dfn[b]) swap(a, b); ///保证a比b的深度深
ans += query(dfn[a], dfn[b]); ///他们已经在一条重链上了
return ans;
}
void solve()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%lld", &ori[i]);
for(int i = 1, v, u; i < n; ++i) {
scanf("%d%d",&u, &v);
e[u].pb(v);
e[v].pb(u);
}
dfs1(1, 0);
dfs2(1, 1);
build();
while(m--)
{
int op, a, b, c;
scanf("%d", &op);
if(op == 1) {
scanf("%d%d", &a, &b);
update(dfn[a], dfn[a], b);
///用区间修改也可以实现单点修改
}
else if(op == 2) {
scanf("%d%d", &a, &b);
update(dfn[a], dfn[a]+siz[a]-1, b);
///修改a以及子树,都加b
}
else {
scanf("%d", &a);
printf("%lld\n", Query_sum(1, a));
///统计root(1)到a的权值和
}
}
}
int main(){
// int _; scanf("%d", &_); while(_--)
// while(~scanf("%d", &n))
// while(scanf("%d", &n)&&n)
solve();
return 0;
}
树链剖分板题acwing 917. 树上操作
猜你喜欢
转载自blog.csdn.net/weixin_44070289/article/details/106812946
今日推荐
周排行