题意:要求在一棵N(<=50000)个带权节点的树上支持3种操作
(1)I u v w,u到v的路径上每个节点权值增加w
(2)D u v w,u到v的路径上每个节点权值减少w
(3)Q u,求u点的权值
思路:
将树剖分成若干条链,然后用区间数据结构来维护,这就是树链剖分。树链剖分后,这个题可以转化为一个“区间修改,单点查询”的问题,树状数组或线段树即可。
树状数组(1100ms):
#pragma comment(linker, "/STACK:10240000,10240000")
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstring>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;
#ifndef ONLINE_JUDGE
#include "local.h"
#endif
const int N = 5e4 + 7;
const int M = N;
namespace Edge {
int last[N], to[M << 1], next[M << 1], cntE;
void init() {
cntE = 0;
memset(last, -1, sizeof(last));
}
void addEdge(int u, int v) {
to[cntE] = v;
next[cntE] = last[u];
last[u] = cntE ++;
}
}
namespace TreeChain {
int dep[N], top[N], w[N], son[N], siz[N], fa[N];
int id[N], rnk[N], cntID;
void init() {
cntID = 0;
memset(son, -1, sizeof(son));
}
void dfs1(int u, int f, int d) {
dep[u] = d;
fa[u] = f;
siz[u] = 1;
for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
int v = Edge::to[i];
if (v != f) {
dfs1(v, u, d + 1);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
}
}
void dfs2(int u, int t) {
top[u] = t;
id[u] = ++ cntID;
rnk[id[u]] = u;
if (son[u] == -1) return;
dfs2(son[u], t);
for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
int v = Edge::to[i];
if (v != son[u] && v != fa[u])
dfs2(v, v);
}
}
}
int a[N];
namespace TreeArray {
int c[N], n;
void init(int n) {
memset(c, 0, sizeof(c));
TreeArray::n = n;
}
int lowbit(int x) { return x & -x; }
void add(int p, int x) {
while (p <= n) {
c[p] += x;
p += lowbit(p);
}
}
void add(int l, int r, int x) {
add(l, x);
add(r + 1, -x);
}
int query(int p) {
int ans = 0;
while (p) {
ans += c[p];
p -= lowbit(p);
}
return ans;
}
void change(int u, int v, int w) {
using namespace TreeChain;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
add(id[top[u]], id[u], w);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
add(id[u], id[v], w);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int n, m, p, u, v, w;
char s[2];
while (cin >> n >> m >> p) {
Edge::init();
TreeChain::init();
for (int i = 1; i <= n; i ++) {
scanf("%d", a + i);
}
for (int i = 0; i < m; i ++) {
scanf("%d%d", &u, &v);
Edge::addEdge(u, v);
Edge::addEdge(v, u);
}
TreeChain::dfs1(1, 0, 0);
TreeChain::dfs2(1, 1);
TreeArray::init(n);
for (int i = 1; i <= n; i ++) {
TreeArray::add(i, i, a[TreeChain::rnk[i]]);
}
for (int i = 0; i < p; i ++) {
scanf("%s", s);
if (*s == 'Q') {
scanf("%d", &u);
printf("%d\n", TreeArray::query(TreeChain::id[u]));
}
else {
scanf("%d%d%d", &u, &v, &w);
if (*s == 'D') w = -w;
TreeArray::change(u, v, w);
}
}
}
return 0;
}
线段树(1900ms):
#pragma comment(linker, "/STACK:10240000,10240000")
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstring>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;
#ifndef ONLINE_JUDGE
#include "local.h"
#endif
const int N = 5e4 + 7;
const int M = N;
namespace Edge {
int last[N], to[M << 1], next[M << 1], cntE;
void init() {
cntE = 0;
memset(last, -1, sizeof(last));
}
void addEdge(int u, int v) {
to[cntE] = v;
next[cntE] = last[u];
last[u] = cntE ++;
}
}
namespace TreeChain {
int dep[N], top[N], w[N], son[N], siz[N], fa[N];
int id[N], rnk[N], cntID;
void init() {
cntID = 0;
memset(son, -1, sizeof(son));
}
void dfs1(int u, int f, int d) {
dep[u] = d;
fa[u] = f;
siz[u] = 1;
for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
int v = Edge::to[i];
if (v != f) {
dfs1(v, u, d + 1);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
}
}
void dfs2(int u, int t) {
top[u] = t;
id[u] = ++ cntID;
rnk[id[u]] = u;
if (son[u] == -1) return;
dfs2(son[u], t);
for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
int v = Edge::to[i];
if (v != son[u] && v != fa[u])
dfs2(v, v);
}
}
}
int a[N];
namespace SegTree {
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
int sum[N << 2], mark[N << 2];
void up(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void down(int rt, int len) {
int rlen = len >> 1, llen = len - rlen;
if (mark[rt]) {
sum[rt << 1] += llen * mark[rt];
mark[rt << 1] += mark[rt];
sum[rt << 1 | 1] += rlen * mark[rt];
mark[rt << 1 | 1] += mark[rt];
mark[rt] = 0;
}
}
void build(int l, int r, int rt) {
mark[rt] = 0;
if (l == r) {
sum[rt] = a[TreeChain::rnk[l]];
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
up(rt);
}
void update(int L, int R, int x, int l, int r, int rt) {
if (L <= l && r <= R) {
sum[rt] += (r - l + 1) * x;
mark[rt] += x;
return;
}
int m = (l + r) >> 1;
down(rt, r - l + 1);
if (L <= m) update(L, R, x, lson);
if (R > m) update(L, R, x, rson);
up(rt);
}
int query(int p, int l, int r, int rt) {
if (l == r) return sum[rt];
int m = (l + r) >> 1;
down(rt, r - l + 1);
if (p <= m) return query(p, lson);
else return query(p, rson);
}
void change(int u, int v, int w, int n) {
using namespace TreeChain;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
update(id[top[u]], id[u], w, 1, n, 1);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
update(id[u], id[v], w, 1, n, 1);
}
#undef lson
#undef rson
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int n, m, p, u, v, w;
char s[2];
while (cin >> n >> m >> p) {
Edge::init();
TreeChain::init();
for (int i = 1; i <= n; i ++) {
scanf("%d", a + i);
}
for (int i = 0; i < m; i ++) {
scanf("%d%d", &u, &v);
Edge::addEdge(u, v);
Edge::addEdge(v, u);
}
TreeChain::dfs1(1, 0, 0);
TreeChain::dfs2(1, 1);
SegTree::build(1, n, 1);
for (int i = 0; i < p; i ++) {
scanf("%s", s);
if (*s == 'Q') {
scanf("%d", &u);
printf("%d\n", SegTree::query(TreeChain::id[u], 1, n, 1));
}
else {
scanf("%d%d%d", &u, &v, &w);
if (*s == 'D') w = -w;
SegTree::change(u, v, w, n);
}
}
}
return 0;
}