LOJ146:
给定一棵
n
n
n 个结点的树,根结点为
r
r
r,初始点权
w
i
w_i
wi,
m
m
m 次操作:
①
1
,
a
,
b
,
x
1, a, b, x
1,a,b,x,
a
a
a 到
b
b
b 最短路径间点权都加上
x
x
x;
②
2
,
a
2, a
2,a,求结点
a
a
a 的点权;
③
3
,
a
3, a
3,a,求结点
a
a
a 子树点权和。
(
n
,
m
≤
1
0
6
)
(n, m \leq 10^6)
(n,m≤106)
LOJ147:
给定一棵
n
n
n 个结点的树,根结点为
r
r
r,初始点权
w
i
w_i
wi,
m
m
m 次操作:
①
1
,
a
,
x
1, a, x
1,a,x,将结点
a
a
a 点权加上
x
x
x;
②
2
,
a
,
x
2, a, x
2,a,x,将结点
a
a
a 子树点权都加上
x
x
x;
③
3
,
a
,
b
3, a, b
3,a,b,求
a
a
a 到
b
b
b 最短路径间点权和。
(
n
,
m
≤
1
0
6
)
(n, m \leq 10^6)
(n,m≤106)
链接:https://loj.ac/problem/147
先考虑第一道题,直接地可以用树链剖分做到
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n),但是这个复杂度是过不去的。只有修改有链操作,将
a
b
ab
ab 路径的修改
+
x
+x
+x,拆成
a
r
ar
ar 路径
+
x
+x
+x、
b
r
br
br 路径
+
x
+x
+x、
l
c
a
(
a
,
b
)
r
lca(a, b)r
lca(a,b)r 路径
−
x
-x
−x、
f
a
(
l
c
a
(
a
,
b
)
)
r
fa(lca(a, b))r
fa(lca(a,b))r 路径
−
x
-x
−x,子问题就是对
a
r
ar
ar 路径上点权
+
x
+x
+x。
对点 a a a 加上 x x x,对询问点 b b b 有贡献,当且仅当 a a a 在 b b b 子树内,那么对 a a a 单点修改 x x x,询问 b b b 则查询子树和(区间查询);
同理,对子树 a a a 加上 x x x,此操作对询问点 b b b 的贡献为 ( d e p a − d e p b + 1 ) ∗ x (dep_a - dep_b + 1) * x (depa−depb+1)∗x,拆成两项 − d e p b ∗ x + ( 1 + d e p a ) ∗ x -dep_b * x + (1 + dep_a) * x −depb∗x+(1+depa)∗x,前一项将 d e p b dep_b depb 提出,单独维护 x x x 的修改,后一项直接为 ( 1 + d e p a ) ∗ x (1 + dep_a) * x (1+depa)∗x 的修改,两个树状数组分别修改维护。
第二道题,只有询问有链操作,按第一道一样拆成
4
4
4 个到根的路径的查询。点
a
a
a 加上
x
x
x,仅当
b
b
b 在
a
a
a 子树内时,
a
a
a 对
b
b
b 有贡献,那么将
a
a
a 子树打上标记
x
x
x(区间修改),差分一下变成两次单点修改,
b
b
b 查询前缀和即是答案。
然后考虑 a a a 子树加上 x x x,同理, a a a 对 b b b 的贡献为 ( d e p b − d e p a + 1 ) ∗ x (dep_b - dep_a + 1) * x (depb−depa+1)∗x,依然拆成 d e p b ∗ x + ( 1 − d e p a ) ∗ x dep_b * x + (1 - dep_a) * x depb∗x+(1−depa)∗x,前一项提取 d e p b dep_b depb 后单独维护,后一项直接为 ( 1 − d e p a ) ∗ x (1 - dep_a) * x (1−depa)∗x 的区间修改。
这两题卡常,需要快读,以及求
L
C
A
LCA
LCA 不能用倍增。
参考代码:
LOJ146:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
vector<int> G[maxn];
int a[maxn], dfn[maxn], dep[maxn], siz[maxn], top[maxn], fa[maxn], son[maxn];
int n, m, rt, tim;
struct BIT{
ll c[maxn];
#define lowb(x) ((x)&(-x))
void update(int x, ll val){
if(x <= 0) return;
while(x <= n) c[x] += val, x += lowb(x);
}
ll query(int x){
ll ret = 0;
while(x) ret += c[x], x -= lowb(x);
return ret;
}
} c1, c2;
void dfs1(int u, int f){
fa[u] = f, dep[u] = dep[f] + 1, siz[u] = 1, son[u] = 0;
for(auto &v : G[u]){
if(v == f) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int t){
dfn[u] = ++tim, top[u] = t;
if(!son[u]) return;
dfs2(son[u], t);
for(auto &v : G[u]){
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int lca(int u, int v){
while(top[u] != top[v]){
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
const int maxs = 1e3 + 5;
char buf[maxs], *p1 = buf, *p2 = buf;
inline char fr(){
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, maxs, stdin)) == p1 ? -1 : *p1++;
}
#define gc fr()
inline void read(int &x){
char ch; int flg = 0; while(!isdigit(ch = gc)) flg = ch == '-' ? 1 : flg;
x = ch ^ 48; while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48); x = flg ? -x : x;
}
void update(int u, int v, ll val){
int lc = lca(u, v), flc = fa[lc];
c1.update(dfn[u], val);
c1.update(dfn[v], val);
c1.update(dfn[lc], -val);
c1.update(dfn[flc], -val);
c2.update(dfn[u], val * (dep[u] + 1));
c2.update(dfn[v], val * (dep[v] + 1));
c2.update(dfn[lc], -val * (dep[lc] + 1));
c2.update(dfn[flc], -val * (dep[flc] + 1));
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
read(n), read(m), read(rt);
for(int i = 1; i <= n; ++i){
read(a[i]);
}
for(int i = 1; i < n; ++i){
int u, v; read(u), read(v);
G[u].pb(v), G[v].pb(u);
}
dfs1(rt, 0);
dfs2(rt, rt);
for(int i = 1; i <= n; ++i){
update(i, i, a[i]);
}
while(m--){
int opt, x, y, z; read(opt), read(x);
if(opt == 1){
read(y), read(z);
update(x, y, z);
}
else if(opt == 2){
ll ret = c1.query(dfn[x] + siz[x] - 1);
ret -= c1.query(dfn[x] - 1);
printf("%lld\n", ret);
}
else{
ll ret = c2.query(dfn[x] + siz[x] - 1) - c2.query(dfn[x] - 1);
ret -= dep[x] * (c1.query(dfn[x] + siz[x] - 1) - c1.query(dfn[x] - 1));
printf("%lld\n", ret);
}
}
return 0;
}
LOJ147:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
vector<int> G[maxn];
int a[maxn], dfn[maxn], siz[maxn], dep[maxn], fa[maxn], top[maxn], son[maxn];
int n, m, rt, tim;
struct BIT{
ll c[maxn];
#define lowb(x) ((x)&(-x))
void update(int x, ll val){
if(x <= 0) return;
while(x <= n) c[x] += val, x += lowb(x);
}
ll query(int x){
ll ret = 0;
while(x) ret += c[x], x -= lowb(x);
return ret;
}
} c1, c2;
void dfs1(int u, int f){
fa[u] = f, dep[u] = dep[f] + 1, siz[u] = 1, son[u] = 0;
for(auto &v : G[u]){
if(v == f) continue;
dfs1(v, u);
siz[u] += siz[v];
son[u] = siz[v] > siz[son[u]] ? v : son[u];
}
}
void dfs2(int u, int t){
dfn[u] = ++tim, top[u] = t;
if(!son[u]) return;
dfs2(son[u], t);
for(auto &v : G[u]){
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int lca(int u, int v){
while(top[u] != top[v]){
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
ll query(int u, int v){
int lc = lca(u, v), flc = fa[lc];
ll ret = 0;
ret += c1.query(dfn[u]) + c1.query(dfn[v]);
ret -= c1.query(dfn[lc]) + c1.query(dfn[flc]);
ret += dep[u] * c2.query(dfn[u]) + dep[v] * c2.query(dfn[v]);
ret -= dep[lc] * c2.query(dfn[lc]) + dep[flc] * c2.query(dfn[flc]);
return ret;
}
const int maxs = 1e3 + 5;
char buf[maxs], *p1 = buf, *p2 = buf;
inline char fr(){
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, maxs, stdin)) == p1 ? -1 : *p1++;
}
#define gc fr()
inline void read(int &x){
char ch; int flg = 0; while(!isdigit(ch = gc)) flg = ch == '-' ? 1 : flg;
x = ch ^ 48; while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48); x = flg ? -x : x;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
read(n), read(m), read(rt);
for(int i = 1; i <= n; ++i){
read(a[i]);
}
for(int i = 1; i < n; ++i){
int u, v; read(u), read(v);
G[u].pb(v), G[v].pb(u);
}
dfs1(rt, 0);
dfs2(rt, rt);
for(int i = 1; i <= n; ++i){
c1.update(dfn[i], a[i]);
c1.update(dfn[i] + siz[i], -a[i]);
}
while(m--){
int opt, x, y; read(opt), read(x), read(y);
if(opt == 1){
c1.update(dfn[x], y);
c1.update(dfn[x] + siz[x], -y);
}
else if(opt == 2){
c1.update(dfn[x], y * 1ll * (1 - dep[x]));
c1.update(dfn[x] + siz[x], -y * 1ll * (1 - dep[x]));
c2.update(dfn[x], y);
c2.update(dfn[x] + siz[x], -y);
}
else{
ll ret = query(x, y);
printf("%lld\n", ret);
}
}
return 0;
}