4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 5443 Solved: 1742
[ Submit][ Status][ Discuss]
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
Source
裸的树剖+线段树用这题尝试了一下线段树标记永久化,蛮好玩的
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define maxn 101001
#define ls p << 1
#define rs p << 1 | 1
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int pre[maxn], top;
struct edge {
int to, next;
void add(int a, int b) {
to = b;
next = pre[a];
pre[a] = top++;
}
}e[maxn << 1];
int n, m, tot;
int f[maxn], d[maxn], in[maxn], out[maxn], deep[maxn], son[maxn], dson[maxn], w[maxn];
long long lazy[maxn * 8], sum[maxn * 8];
void adds(int u, int v)
{
e[top].add(u, v);
e[top].add(v, u);
}
void dfs1(int u, int fa) {
f[u] = fa; deep[u] = deep[fa] + 1; son[u] = 1; dson[u] = 0;
for(int i = pre[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if(v == fa) continue;
dfs1(v, u);
son[u] += son[v];
if(son[v] > son[dson[u]]) dson[u] = v;
}
}
void dfs2(int u, int chain) {
out[u] = in[u] = ++tot; d[u] = chain;
if(!dson[u]) return;
dfs2(dson[u], chain);
for(int i = pre[u]; ~i; i = e[i].next)
if(e[i].to != f[u] && e[i].to != dson[u])
dfs2(e[i].to, e[i].to);
out[u] = tot;
}
void Seg_ch(int p, int st, int ed, int L, int R, int val) {
if(L == st && R == ed) {
lazy[p] += val;
return;
}
int mid = L + R >> 1; sum[p] += (long long)(ed - st + 1) * val;
if(st <= mid) Seg_ch(ls, st, min(mid, ed), L, mid, val);
if(ed > mid) Seg_ch(rs, max(mid + 1, st), ed, mid + 1, R, val);
}
long long Seg_sum(int p, int st, int ed, int L, int R) {
if(L == st && R == ed) return sum[p] + lazy[p] * (ed - st + 1);
int mid = L + R >> 1;
long long ans = lazy[p] * (long long)(ed - st + 1);
if(st <= mid) ans += Seg_sum(ls, st, min(mid, ed), L, mid);
if(ed > mid) ans += Seg_sum(rs, max(mid + 1, st), ed, mid + 1, R);
return ans;
}
void init() {
memset(pre, -1, sizeof(pre)); top = 0;
n = read(); m = read();
for(int i = 1;i <= n; ++i) w[i] = read();
for(int i = 1;i < n; ++i) adds(read(), read());
dfs1(1, 0); dfs2(1, 1);
for(int i = 1;i <= n; ++i) Seg_ch(1, in[i], in[i], 1 , n, w[i]);
}
long long query(int u) {
long long ans = 0;
while(u) {
ans += Seg_sum(1, in[d[u]], in[u], 1, n);
u = f[d[u]];
}
return ans;
}
void solve() {
while(m--) {
int opt = read(), x = read();
if(opt == 1) Seg_ch(1, in[x], in[x], 1, n, read());
if(opt == 2) Seg_ch(1, in[x], out[x], 1, n, read());
if(opt == 3) printf("%lld\n", query(x));
}
}
int main()
{
init();
solve();
return 0;
}