bzoj1036: [ZJOI2008]树的统计Count
2015-10-23 19:12
399 查看
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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
41 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
41
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
相关文章推荐
- php手册之clone
- ubuntu14下编译android jrtplib
- NVIDIA TEGRA3与PhysX技术在UNITY引擎的使用及优化技巧
- 基于递归下降分析法自制计算器
- HDU 2147 kiki's game
- orgmode文档直接knitr输出HTML或PDF
- Spring4 学习笔记(3)-Spring 基于 XML 的方式配置 Bean(供自己学习)
- 【POJ3182】The Grove BFS 最短路径周围
- 内存、优化工具若干
- True(False) Positives (Negatives), 召回率和精度定义
- springmvc返回.html页面报404
- Linux netstat命令详解
- 【Android先进】查看手机记忆库状态和应用方法
- 第一课初始Servlet
- 设计模式宏观概述(一)
- leetcode Combination Sum II
- switch语句及其注意事项
- Linux学习19_每天一个linux命令(10):cat 命令
- APP Profiler
- 网易cc题2