1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8880 Solved: 3618
[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
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
树链剖分裸题,好久没写了练下手。
话说我树链剖分代码一直很长,是我姿势不对还是说这算法就这么麻烦呢。
代码如下:
1
2
2
10
6
5
6
5
16
树链剖分裸题,好久没写了练下手。
话说我树链剖分代码一直很长,是我姿势不对还是说这算法就这么麻烦呢。
代码如下:
/**************************************************************
Problem: 1036
User: duyixian
Language: C++
Result: Accepted
Time:2348 ms
Memory:10616 kb
****************************************************************/
/*
* @Author: duyixian
* @Date: 2015-10-02 15:25:01
* @Last Modified by: duyixian
* @Last Modified time: 2015-10-04 16:49:08
*/
#include "cstdio"
#include "cstdlib"
#include "iostream"
#include "algorithm"
#include "cstring"
#include "queue"
using namespace std;
#define MAX_SIZE 70005
#define INF 0x3F3F3F3F
#define Eps
#define Mod
inline int Get_Int()
{
int Num = 0, Flag = 1;
char ch;
do
{
ch = getchar();
if(ch == '-')
Flag *= -1;
}
while(ch < '0' || ch > '9');
do
{
Num = Num * 10 + ch - '0';
ch = getchar();
}
while(ch >= '0' && ch <= '9');
return Num * Flag;
}
struct Edge
{
int To, Next;
}Edges[MAX_SIZE];
int N, Q, Total;
int Front[MAX_SIZE], Depth[MAX_SIZE], Father[MAX_SIZE], Location[MAX_SIZE], Son[MAX_SIZE], Size[MAX_SIZE], Top[MAX_SIZE], Value[MAX_SIZE], Order[MAX_SIZE];
struct Node
{
int Left, Right, Mid, Sum, Max;
};
struct Segment_Tree
{
Node Nodes[MAX_SIZE * 4];
inline void Update(int Now)
{
Nodes[Now].Max = max(Nodes[Now << 1].Max, Nodes[(Now << 1) + 1].Max);
Nodes[Now].Sum = Nodes[Now << 1].Sum + Nodes[(Now << 1) + 1].Sum;
}
void Build(int Left, int Right, int Now)
{
Nodes[Now].Left = Left;
Nodes[Now].Right = Right;
Nodes[Now].Mid = Left + Right >> 1;
if(Left == Right)
{
Nodes[Now].Max = Nodes[Now].Sum = Value[Left];
return;
}
Build(Left, Nodes[Now].Mid, Now << 1);
Build(Nodes[Now].Mid + 1, Right, (Now << 1) + 1);
Update(Now);
}
inline void Build()
{
Build(1, N, 1);
}
void Change(int Location, int Value, int Now)
{
if(Nodes[Now].Left == Nodes[Now].Right)
{
Nodes[Now].Sum = Nodes[Now].Max = Value;
return;
}
int i = Location > Nodes[Now].Mid;
Change(Location, Value, (Now << 1) + i);
Update(Now);
}
inline void Change(int Location, int Value)
{
Change(Location, Value, 1);
}
int Ask(int Left, int Right, int Flag, int Now)
{
if(Nodes[Now].Left == Left && Nodes[Now].Right == Right)
{
if(Flag == 1)
return Nodes[Now].Sum;
return Nodes[Now].Max;
}
if(Right <= Nodes[Now].Mid || Left > Nodes[Now].Mid)
{
int i = Left > Nodes[Now].Mid;
return Ask(Left, Right, Flag, (Now << 1) + i);
}
int temp1 = Ask(Left, Nodes[Now].Mid, Flag, Now << 1), temp2 = Ask(Nodes[Now].Mid + 1, Right, Flag, (Now << 1) + 1);
if(Flag == 1)
return temp1 + temp2;
return max(temp1, temp2);
}
inline int Ask(int Left, int Right, int Flag)
{
return Ask(Left, Right, Flag, 1);
}
}Tree;
inline void Add_Edge(int From, int To)
{
Edges[++Total].To = To;
Edges[Total].Next = Front[From];
Front[From] = Total;
}
inline void Add_Edges(int From, int To)
{
Add_Edge(From, To);
Add_Edge(To, From);
}
void DFS1(int Now)
{
Size[Now] = 1;
Depth[Now] = Depth[Father[Now]] + 1;
for(int i = Front[Now]; i; i = Edges[i].Next)
{
if(Edges[i].To == Father[Now])
continue;
Father[Edges[i].To] = Now;
DFS1(Edges[i].To);
if(Size[Edges[i].To] > Size[Son[Now]])
Son[Now] = Edges[i].To;
Size[Now] += Size[Edges[i].To];
}
}
void DFS2(int Now, int top)
{
Order[++Total] = Now;
Location[Now] = Total;
Top[Now] = top;
if(Son[Now])
DFS2(Son[Now], top);
for(int i = Front[Now]; i; i = Edges[i].Next)
{
if(Edges[i].To == Father[Now] || Edges[i].To == Son[Now])
continue;
DFS2(Edges[i].To, Edges[i].To);
}
}
inline int Ask(int x, int y, int Flag)
{
int Ans = 0, temp;
if(Flag == 2)
Ans = -INF;
while(Top[x] != Top[y])
{
if(Depth[Top[x]] < Depth[Top[y]])
swap(x, y);
temp = Tree.Ask(Location[Top[x]], Location[x], Flag);
if(Flag == 1)
Ans += temp;
else
Ans = max(Ans, temp);
x = Father[Top[x]];
}
if(Depth[x] < Depth[y])
swap(x, y);
temp = Tree.Ask(Location[y], Location[x], Flag);
if(Flag == 1)
Ans += temp;
else
Ans = max(Ans, temp);
return Ans;
}
int main()
{
cin >> N;
for(int i = 1; i < N; ++i)
Add_Edges(Get_Int(), Get_Int());
Total = 0;
DFS1(1);
DFS2(1, 1);
for(int i = 1; i <= N; ++i)
Value[Location[i]] = Get_Int();
Tree.Build();
cin >> Q;
for(int i = 1; i <= Q; ++i)
{
char Op[10];
int a, b;
scanf("%s", Op);
a = Get_Int(), b = Get_Int();
if(Op[0] == 'C')
Tree.Change(Location[a], b);
else if(Op[1] == 'S')
printf("%d\n", Ask(a, b, 1));
else
printf("%d\n", Ask(a, b, 2));
}
return 0;
}