HDU 3966
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3966
题意:
n个(<=1e5)兵营,以树的形式相互连接构成连通图。给出初始每个兵营的兵数量。
然后有修改操作,即u-v的路径上(包括u,v)经过的兵营兵的数量全减少或增加某一个值。
有查询操作,求一个兵营当前兵的数量。输出这个数量。
思路:
裸的树链剖分。
各种写错。
容易T的地方:
1)solve处的u=fa[tp1]写成u=fa[u]
2)Solve处各种写反
容易WA的地方:
1)solve处u=v则退出
2)建线段树时,tree[o].val = val[id[l]]而不是tree[o].val = val[tid[l]](要用一个新的指针指回去,搞清楚线段树中这个点到底是哪一个点)
3)线段树更新时没有及时push_down。
源码:
#pragma comment(linker,"/STACK:100000000,100000000")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 50000 + 5;
int tp[MAXN], fa[MAXN], num[MAXN], son[MAXN], dep[MAXN];
int id[MAXN], cnt, tid[MAXN];
vector<int>lin[MAXN];
void dfs1(int u, int f, int deep)
{
num[u] = 1, fa[u] = f, son[u] = 0, dep[u] = deep;
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
if(v == f) continue;
dfs1(v, u, deep + 1);
num[u] += num[v];
if(num[son[u]] < num[v]) son[u] = v;
}
}
void dfs2(int u, int f)
{
id[u] = ++cnt;
tid[cnt] = u;
tp[u] = f;
if(son[u]) dfs2(son[u], f);
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
struct Tree
{
int l, r, val;
int add;
}tree[MAXN * 4];
int val[MAXN];
void build(int l, int r, int o)
{
tree[o].l = l, tree[o].r = r, tree[o].add = 0, tree[o].val = 0;
if(l == r){
tree[o].val = val[tid[l]];
return;
}
int mid = (l + r) / 2;
if(mid >= l) build(l, mid, o * 2);
if(mid < r) build(mid + 1, r, o * 2 + 1);
}
void push_down(int o)
{
if(tree[o].add == 0) return;
tree[o * 2].add += tree[o].add;
tree[o * 2 + 1].add += tree[o].add;
tree[o].add = 0;
}
int query(int u, int o)
{
// printf("u = %d, o = %d\n", u, o);
// printf("tree[o].l = %d, tree[o].r = %d\n", tree[o].l, tree[o].r);
// system("pause");
if(tree[o].l == tree[o].r && tree[o].l == u){
return tree[o].add + tree[o].val;
}
int ans = 0;
push_down(o);
int mid = (tree[o].l + tree[o].r) / 2;
if(mid >= u) ans = query(u, o * 2);
else ans = query(u, o * 2 + 1);
return ans;
}
void update(int l, int r, int val, int o)
{
// if(tree[o].r < l || tree[o].l > r) return;
// printf("l = %d, r = %d, val = %d, tree[o].l = %d, tree[o].r = %d, o = %d\n", l, r, val, tree[o].l, tree[o].r, o);
// system("pause");
if(tree[o].l >= l && tree[o].r <= r){
tree[o].add += val;
return;
}
push_down(o);
int mid = (tree[o].l + tree[o].r) / 2;
if(mid < l) update(l, r, val, o * 2 + 1);
else if(mid >= r) update(l, r, val, o * 2);
else{
update(l, r, val, o * 2);
update(l, r, val, o * 2 + 1);
}
}
void solve(int u, int v, int val)
{
int tp1 = tp[u], tp2 = tp[v];
while(tp1 != tp2){
if(dep[tp1] < dep[tp2]) swap(tp1, tp2), swap(u, v);
update(id[tp1], id[u], val, 1);
u = fa[tp1];
tp1 = tp[u];
}
if(dep[u] > dep[v]) swap(u, v);
update(id[u], id[v], val, 1);
}
char op[1000];
int main()
{
int n, m, q;
while(scanf("%d%d%d", &n, &m, &q) != EOF){
for(int i = 0 ; i <= n ; i++) lin[i].clear();
int u, v, w;
for(int i = 1 ; i <= n ; i++) scanf("%d", &val[i]);
for(int i = 0 ; i < m ; i++){
scanf("%d%d", &u, &v);
lin[u].push_back(v);
lin[v].push_back(u);
}
cnt = 0;
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, n, 1);
while(q--){
scanf("%s", op);
if(op[0] == 'Q'){
scanf("%d", &u);
// printf("first = %d, second = %d\n", query(id[u], 1), val[id[u]]);
printf("%d\n", query(id[u], 1));
}
else{
scanf("%d%d%d", &u, &v, &w);
if(op[0] == 'D') solve(u, v, -w);
else solve(u, v, w);
}
}
}
return 0;
}