【SPOJ375】 Query on a tree——树链剖分

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3…N-1.

We will ask you to perfrom some instructions of the following form:

CHANGE i ti : change the cost of the i-th edge to ti
or
QUERY a b : ask for the maximum edge cost on the path from node a to node b
Input

The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.

For each test case:

In the first line there is an integer N (N <= 10000),
In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
The next lines contain instructions “CHANGE i ti” or “QUERY a b”,
The end of each test case is signified by the string “DONE”.
There is one blank line between successive tests.

Output

For each “QUERY” operation, write one integer representing its result.

Example

Input:
1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Output:
1
3

第一道树链剖分的题,写的超时了,后来发现是在查询的时候写错了。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <queue>
#include <algorithm>

using namespace std;

const int Max = 10100;

typedef struct node
{
    int v,w,next;
}Edge;

typedef struct Node
{
    int u, v, w;
}Point;

Point P[Max];

Edge E[Max*3];

int Tr[Max*8];//线段树

int H[Max],top;//前向星

int Dep[Max];//结点的深度

int Fa[Max];//结点的父亲

int Size[Max];//以结点为根的树的节点的个数

int Son[Max];//结点的儿子

int Tid[Max];//结点在线段树中的编号

int Top[Max];//结点所在重链的首节点

void AddEdge(int u, int v, int w)//建树
{
    E[top].v = v; E[top].w = w; E[top].next = H[u];

    H[u] = top++;

    E[top].v = u; E[top].w = w; E[top].next = H[v];

    H[v] = top++;
}

void dfs1(int u,int fa,int dep)//第一遍dfs记录结点的深度,父亲,重儿子,大小
{
    Dep[u] = dep;

    Fa[u] = fa;

    Size[u] = 1;

    Son[u] = 0;

    for(int i = H[u]; ~i ;i = E[i].next)
    {
        if(E[i].v != fa)
        {
            dfs1(E[i].v,u,dep+1);

            Size[u]+=Size[E[i].v];

            if(Son[u]==0||Size[E[i].v]>Size[Son[u]]) Son[u] = E[i].v;
        }
    }
}

int tim;

void dfs2(int u,int fa)//第二遍dfs给结点编号和构建重链
{
    Tid[u] = ++tim;

    Top[u] = fa;

    if(Son[u]) dfs2(Son[u],fa);

    for(int i = H[u];~i; i = E[i].next)
    {
        if(E[i].v != Fa[u] && E[i].v!=Son[u])

            dfs2(E[i].v,E[i].v);
    }
}

void PushUp(int st)
{
    Tr[st] = max(Tr[st<<1],Tr[st<<1|1]);
}

void BuildSegTree(int L,int R,int st)
{
    Tr[st] = 0;

    if(L == R) return;

    int mid = (L + R)>>1;

    BuildSegTree(L,mid,st<<1);

    BuildSegTree(mid+1,R,st<<1|1);

}

void Update(int L,int R,int st,int d,int val)
{
    if(L == R) 
    {
        Tr[st] = val ; 

        return ;
    }

    int mid = (L + R)>>1;

    if(d<=mid) Update(L,mid,st<<1,d,val);

    else Update(mid+1,R,st<<1|1,d,val);

    PushUp(st);

}

int Query(int L,int R,int st,int l,int r)
{
    if(L==l&&R==r) return Tr[st];

    int mid = (L + R)>>1;

    if(r<=mid) return Query(L,mid,st<<1,l,r);

    else if(l>mid) return Query(mid+1,R,st<<1|1,l,r);

    else return max(Query(L,mid,st<<1,l,mid),Query(mid+1,R,st<<1|1,mid+1,r));
}

int Find(int u,int v)
{
    int ans = 0 ;

    while(Top[u] != Top[v])
    {
        if(Dep[Top[u]]>Dep[Top[v]])//每一次将深度大的提高
        {
            swap(u,v);
        }

        ans = max(ans,Query(1,tim,1,Tid[Top[v]],Tid[v]));

        v = Fa[Top[v]];
    }

    if(u==v) return ans;

    if(Dep[u]>Dep[v])

        swap(u,v);

    ans = max(ans,Query(1,tim,1,Tid[Son[u]],Tid[v]));

    return ans;
}

int main()
{
    int T;

    int n;

    int u, v, w;

    char Op[20];

    scanf("%d",&T);

    while(T--)
    {
        scanf("%d",&n);

        memset(H,-1,sizeof(H));

        memset(Son,0,sizeof(Son));

        top = 0;tim = 0 ;

        for(int i = 1; i < n; i++)
        {
            scanf("%d %d %d",&P[i].u,&P[i].v,&P[i].w);

            AddEdge(P[i].u,P[i].v,P[i].w);
        }

        dfs1(1,-1,0);

        dfs2(1,1);

        BuildSegTree(1,tim,1);//初始化线段树

        for(int i = 1;i<n;i++)
        {
            if(Dep[P[i].u]>Dep[P[i].v]) swap(P[i].u,P[i].v);

            Update(1,tim,1,Tid[P[i].v],P[i].w);//根据新的编号,将重链放进线段树
        }

        while(scanf("%s",Op)&&strcmp(Op,"DONE")!=0)
        {
            if(Op[0]=='Q')
            {
                scanf("%d %d",&u,&v);

                printf("%d\n",Find(u,v));
            }
            else
            {
                scanf("%d %d",&u,&w);

                Update(1,tim,1,Tid[P[u].v],w);
            }
        }

    }
    return 0;
}

你可能感兴趣的:(【SPOJ375】 Query on a tree——树链剖分)