2020.5.9
写完这篇题解去吃饭去。
被这道题搞得有些怀疑人生了。关键问题是对于“根节点”的定义,我以为是节点x的子树的总权值,因为对不上样例还怀疑了下自己用的线段树板子,写了一上午总算确认了自己写的板子没错(我的线段树是郭神和普通线段树的结合版,虽然用这个过了好多题但是每次还是不太敢确定是不是对的)。换了个风格。
我树剖才写过,怎么可能有问题?再读题,卧槽,这个根节点不是指的是1吧?完犊子哦。改了一发就对上了,然后顺利AC。
我下午把另一道题也写一下。我队前任队长去斯坦福了,我这个现任队长也要加油了(虽然这学期gpa本来能满,结果遇到个坑爹老师不回邮件不改作业给低分=。=)。奥利给。
代码:
#include <bits/stdc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define FASTIO ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%lld\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(int i = a ; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 998244353
#define FOPEN freopen("C:\\Users\\administrator01\\CLionProjects\\untitled24\\data.txt", "rt", stdin)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
ll sign = 1, x = 0;char s = getchar();
while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
return x * sign;
}//快读
void write(ll x){
if(x / 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m, rt;
ll tree[limit<<2], inc[limit<<2], val[limit], w[limit];
int id[limit] , fa[limit],depth[limit], eid[limit] , head[limit], cnt, number, son[limit],sizes[limit],top[limit];
struct node{
int to, next;
}edge[limit<<1];
void init(){
number = cnt = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v){
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void dfs(int u, int pre){
sizes[u] = 1;
depth[u] = depth[pre] + 1;
fa[u] = pre;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
if(v != pre){
dfs(v, u);
sizes[u] += sizes[v];
if(sizes[son[u]] < sizes[v])son[u] = v;//重链剖分
}
}
}
void dfs2(int u, int topp){
top[u] = topp;
id[u] = ++number;
w[id[u]] = val[u];//交换
if(son[u]){
dfs2(son[u], topp);
}
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
if(v != son[u] && v != fa[u]){
dfs2(v, v);//轻链剖分
}
}
eid[u] = number;//记录最后
}
void pushup(int root){
tree[root] = tree[root<<1] + tree[root<<1 | 1];//加起来
}
void pushdown(int root, int mid){
if(inc[root]){
inc[root<<1] += inc[root];
inc[root<<1|1] += inc[root];
tree[root<<1] += (mid - (mid>>1)) * inc[root];
tree[root<<1|1] += (mid>>1) * inc[root];
inc[root] = 0;
}
}
void build(int root, int l, int r){
if(l == r){
tree[root] = w[l];
return;
}
int mid = l + (r - l) / 2;
build(root << 1, l , mid);
build(root<<1|1, mid + 1 , r);
inc[root] = 0;
pushup(root);
}
void update(int root, int L, int R, int l, int r, ll val){
if(L <= l && R >= r){
tree[root] += (r - l + 1) * val;
inc[root] += val;
return;
}
int mid = l + (r - l) / 2;
pushdown(root, r - l + 1);
if(L <= mid){
update(root<<1, L, R, l, mid, val);
}
if(R > mid){
update(root<<1|1, L,R,mid + 1, r, val);
}
pushup(root);
}
ll query(int root, int L, int R, int l, int r){
if(L <= l && R >= r){
return tree[root];
}
int mid = l + (r - l) / 2;
pushdown(root,r - l + 1);
ll ans = 0;
if(L <= mid){
ans += query(root<<1, L, R, l, mid);
}
if(R > mid){
ans += query(root<<1|1, L, R, mid + 1 , r);
}
pushup(root);
return ans;
}
ll tree_q(int x){
ll ans = 0;
while(x){
ans += query(1, id[top[x]], id[x], 1, n);
x = fa[top[x]];
}
return ans;
}
int main(){
#ifdef LOCAL
FOPEN;
//freopen("C:\\Users\\administrator01\\CLionProjects\\untitled24\\out.txt", "w", stdout);
#endif
n = read(), m = read();
init();
rep(i ,1, n){
val[i] = read();
}
rep(i, 1, n-1){
int a = read(), b = read();
add(a, b);
add(b, a);
}
dfs(1,0);
dfs2(1,1);
build(1,1,n);
while(m--){
int op = read();
if(op == 1){
ll u = read(), v = read();
update(1, id[u], id[u], 1, n, v);
}else if(op == 2){
ll u = read(), v = read();
update(1, id[u],eid[u],1,n ,v);
}else{
int u = read();
ff(tree_q(u))
}
}
return 0;
}