BZOJ1036 ZJOI2008 樹的統計

1036: [ZJOI2008]樹的統計Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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

Sample Output

4
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;
}



發佈了43 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章