您的位置:首页 > 其它

bzoj1036: [ZJOI2008]树的统计Count

2015-10-23 19:12 399 查看

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 9113 Solved: 3695
[Submit][Status][Discuss]

Description

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4

1 2

2 3

4 1

4 2 1 3

12

QMAX 3 4

QMAX 3 3

QMAX 3 2

QMAX 2 3

QSUM 3 4

QSUM 2 1

CHANGE 1 5

QMAX 3 4

CHANGE 3 6

QMAX 3 4

QMAX 2 4

QSUM 3 4

Sample Output

4

1

2

2

10

6

5

6

5

16

HINT

Source

树的分治

分析:很简单的一道题,块状树、动态树、树链剖分、主席树等等等等
我只写了动态树和树链剖分
动态树就是把链用Splay的形式存起来,利用Splay的特点,然后用左孩子表示此点上面的点,右孩子表示下面的点
树链剖分就是用线段树维护一条条重链,实现时维护一个类似于dfs序列的东西,然后在这个上面建个线段树。

动态树代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <ctime>
using namespace std;
typedef long long LL;
typedef double DB;
#define For(i, s, t) for(int i = (s); i <= (t); i++)
#define Ford(i, s, t) for(int i = (s); i >= (t); i--)
#define Rep(i, t) for(int i = (0); i < (t); i++)
#define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
#define rep(i, x, t) for(int i = (x); i < (t); i++)
#define MIT (2147483647)
#define INF (1000000001)
#define MLL (1000000000000000001LL)
#define sz(x) ((int) (x).size())
#define clr(x, y) memset(x, y, sizeof(x))
#define puf push_front
#define pub push_back
#define pof pop_front
#define pob pop_back
#define ft first
#define sd second
#define mk make_pair
inline void SetIO(string Name) {
string Input = Name+".in",
Output = Name+".out";
freopen(Input.c_str(), "r", stdin),
freopen(Output.c_str(), "w", stdout);
}

inline int Getint() {
int Ret = 0;
char Ch = ' ';
bool Flag = 0;
while(!(Ch >= '0' && Ch <= '9')) {
if(Ch == '-') Flag ^= 1;
Ch = getchar();
}
while(Ch >= '0' && Ch <= '9') {
Ret = Ret*10+Ch-'0';
Ch = getchar();
}
return Flag ? -Ret : Ret;
}

const int N = 30010, M = 16;
int n, m, Arr
;
int First
, To[N*2], Next[N*2], Edges;
int Que
, Len, Size
, Son
;
int Dep
, Fa
, Index
, Root
, Who
;
struct SegType {
int Max, Sum, Child[2];
#define Max(x) (Seg[x].Max)
#define Sum(x) (Seg[x].Sum)
#define Child(x, y) (Seg[x].Child[y])
#define Lc(x) (Seg[x].Child[0])
#define Rc(x) (Seg[x].Child[1])
} Seg[N*M];
int Tot;

inline void Insert(int u, int v) {
Edges++;
To[Edges] = v, Next[Edges] = First[u];
First[u] = Edges;
}

inline void Input() {
n = Getint();
For(i, 1, n-1) {
int x = Getint();
int y = Getint();
Insert(x, y), Insert(y, x);
}
For(i, 1, n) Arr[i] = Getint();
}

inline void Bfs() {
int Head = 1, Tail = 1;
Que[1] = 1, Dep[1] = 1;
while(Head <= Tail) {
int u = Que[Head++];
for(int Tab = First[u], v; Tab; Tab = Next[Tab])
if(!Dep[v = To[Tab]]) {
Dep[v] = Dep[u]+1, Fa[v] = u;
Que[++Tail] = v;
}
}

Ford(i, n, 1) {
int x = Que[i];
Size[x]++;
if(Fa[x]) {
Size[Fa[x]] += Size[x];
if(Size[Son[Fa[x]]] < Size[x])
Son[Fa[x]] = x;
}
}

Index[1] = 1, Root[1] = 1;
For(i, 1, n) {
int x = Que[i];
if(!Son[x]) continue;
Index[Son[x]] = Index[x]+1, Root[Son[x]] = Root[x];
int Cnt = Index[x]+Size[Son[x]];
for(int Tab = First[x], v; Tab; Tab = Next[Tab]) {
v = To[Tab];
if(v != Son[x] && v != Fa[x]) {
Index[v] = Cnt+1, Root[v] = v;
Cnt += Size[v];
}
}
}
For(i, 1, n) Who[Index[i]] = i;
}

inline void Updata(int x) {
Max(x) = -INF, Sum(x) = 0;
Rep(i, 2)
Max(x) = max(Max(x), Max(Child(x, i))),
Sum(x) += Sum(Child(x, i));
}

inline int Build(int Left, int Right) {
int x = ++Tot, Mid = (Left+Right)>>1;
if(Left == Right) Max(x) = Sum(x) = Arr[Who[Left]];
else {
Lc(x) = Build(Left, Mid);
Rc(x) = Build(Mid+1, Right);
Updata(x);
}
return x;
}

inline void Calc(int &Ret, int Tmp, int Type) {
if(Type) Ret += Tmp;
else Ret = max(Ret, Tmp);
}

inline int Query(int x, int L, int R, int Left, int Right, int Type) {
int Ret = Type ? 0 : -INF;
if(L >= Left && R <= Right)
Calc(Ret, Type ? Sum(x) : Max(x), Type);
else {
int Mid = (L+R)>>1, Tmp;
if(Right <= Mid)
Ret = Query(Lc(x), L, Mid, Left, Right, Type);
else if(Left > Mid)
Ret = Query(Rc(x), Mid+1, R, Left, Right, Type);
else {
Tmp = Query(Lc(x), L, Mid, Left, Mid, Type);
Calc(Ret, Tmp, Type);
Tmp = Query(Rc(x), Mid+1, R, Mid+1, Right, Type);
Calc(Ret, Tmp, Type);
}
}
return Ret;
}

inline void Change(int x, int L, int R, int k, int v) {
if(L == R) Sum(x) = Max(x) = v;
else {
int Mid = (L+R)>>1;
if(k <= Mid) Change(Lc(x), L, Mid, k, v);
else Change(Rc(x), Mid+1, R, k, v);
Updata(x);
}
}

inline void Work(int x, int y, int Type) {
int Ret = Type ? 0 : -INF, Tmp;
while(Root[x] != Root[y]) {
if(Dep[Root[x]] < Dep[Root[y]]) swap(x, y);
Tmp = Query(1, 1, n, Index[Root[x]], Index[x], Type);
Calc(Ret, Tmp, Type);
x = Fa[Root[x]];
}
if(Index[x] > Index[y]) swap(x, y);
Tmp = Query(1, 1, n, Index[x], Index[y], Type);
Calc(Ret, Tmp, Type);

printf("%d\n", Ret);
}

inline void Solve() {
Bfs();
Build(1, n);

m = Getint();
while(m--) {
char Opt = ' ';
while(Opt != 'Q' && Opt != 'C') Opt = getchar();
Opt = getchar();
int x = Getint();
int y = Getint();
if(Opt == 'M') Work(x, y, 0);
else if(Opt == 'S') Work(x, y, 1);
else Change(1, 1, n, Index[x], y);
}
}

int main() {
#ifndef ONLINE_JUDGE
SetIO("1036");
#endif
Input();
Solve();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: