spoj375 树链剖分(单点更新,区间查询)

http://www.spoj.com/problems/QTREE/

QTREE - Query on a tree

no tags

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
/**
spoj375 树链剖分(单点更新,区间查询)
参考:
http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
总结的很经典,树链剖分的第一题建议从它开始
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
///#define debug
using namespace std;
const int maxn=10005;
int fa[maxn],siz[maxn],son[maxn],num[maxn],top[maxn],dep[maxn];
int tree[maxn*4],d[maxn][3];
int n,z;
int head[maxn],ip;
void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}

struct note
{
    int v,w,next;
}edge[maxn*2];

void addedge(int u,int v,int w)
{
    edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++;
}

void dfs(int u,int pre)
{
    son[u]=0,siz[u]=1;
    dep[u]=dep[pre]+1;
    fa[u]=pre;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        dfs(v,u);
        if(siz[v]>siz[son[u]])
            son[u]=v;
        siz[u]+=siz[v];
    }
    #ifdef debug
    printf("%d:siz,son,dep,fa %d %d %d %d\n",u,siz[u],son[u],dep[u],fa[u]);
    #endif
}

void build(int u,int tp)
{
     num[u]=++z,top[u]=tp;
     if(son[u]!=0)
     {
        build(son[u],top[u]);
     }
     for(int i=head[u];i!=-1;i=edge[i].next)
     {
        int v=edge[i].v;
        if(v==fa[u]||v==son[u])continue;
        build(v,v);
     }
     #ifdef debug
     printf("%d num,top %d %d\n",u,num[u],top[u]);
     #endif // debug
}

void update(int root,int l,int r,int loc,int x)
{
    if(l>loc||r<loc)return;
    if(l==r)
    {
        tree[root]=x;
        return;
    }
    int mid=(l+r)>>1;
    update(root<<1,l,mid,loc,x);
    update(root<<1|1,mid+1,r,loc,x);
    tree[root]=max(tree[root<<1],tree[root<<1|1]);
    #ifdef debug
    printf("root,l,r,tree[root]%d %d %d %d\n",root,l,r,tree[root]);
    #endif // debug
}

int maxi(int root,int l,int r,int a,int b)
{
    if(r<a||l>b)return 0;
    if(b>=r&&a<=l)
    {
        return tree[root];
    }
    int mid=(l+r)>>1;
    return max(maxi(root<<1,l,mid,a,b),maxi(root<<1|1,mid+1,r,a,b));
}
int find(int va,int vb)
{
    int f1=top[va],f2=top[vb],tmp=0;
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(va,vb);
        }
        tmp=max(tmp,maxi(1,1,z,num[f1],num[va]));
        va=fa[f1],f1=top[va];
    }
    if(va==vb)return tmp;
    ///两点已经在同一条链上,但是不是同一个点
    if(dep[va]>dep[vb])swap(va,vb);
    return max(tmp,maxi(1,1,z,num[son[va]],num[vb]));
}
int main()
{
   /// freopen("data.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        memset(d,0,sizeof(d));
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            d[i][0]=x,d[i][1]=y,d[i][2]=z;
            addedge(x,y,z);
            addedge(y,x,z);
        }
        int root=(n+1)>>1;
        z=0,dep[0]=0;
        dfs(root,0);
        build(root,root);
        for(int i=1;i<n;i++)
        {
            if(dep[d[i][0]]>dep[d[i][1]])
            {
                swap(d[i][0],d[i][1]);
            }
            update(1,1,z,num[d[i][1]],d[i][2]);
        }
        while(1)
        {
            char c[25];
            scanf("%s",c);
            if(c[0]=='D')break;
            int a,b;
            scanf("%d%d",&a,&b);
            if(c[0]=='Q')
            {
                printf("%d\n",find(a,b));
            }
            else
            {
                update(1,1,z,num[d[a][1]],b);
            }
        }
    }
    return 0;
}

时间: 2024-08-05 04:52:09

spoj375 树链剖分(单点更新,区间查询)的相关文章

HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)

Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes on tree is numbered by 1∼N. Then he is given Q questions like that: ①0 x y:change node x′s value to y ②1 x y:For all the value in the path from x to y,do they

SPOJ - QTREE(树链剖分+单点更新+区间最大值查询)

题意:给出n个点n-1条边的树,有两个操作,一个是查询节点l到r的边的最大值,然后指定边的更改权值. 题解:差不多是树链剖分的模版题,注意每个点表示的边是连向其父亲节点的边. #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int M = 1e4 + 10; struct Edge { int v , next; }edge[M << 1]

poj 2763 Housewife Wind(树链剖分+单点查询+区间修改)

题目链接:http://poj.org/problem?id=2763 题意:给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值. 题解:简单的树链剖分. #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int M = 1e5 + 10; struct Edge { int v , next; }edge[M &

TOJ 2725 See you~(二维树状数组单点更新区间查询)

描述 Now I am leaving hust acm. In the past two and half years, I learned so many knowledge about Algorithm and Programming, and I met so many good friends. I want to say sorry to Mr, Yin, I must leave now ~~>.<~~. I am very sorry, we could not advanc

hdu 1754 线段树 水题 单点更新 区间查询

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 59558    Accepted Submission(s): 23201 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要

hdu 3308 线段树 区间合并+单点更新+区间查询

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6592    Accepted Submission(s): 2866 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

【2018年全国多校算法寒假训练营练习比赛(第五场)-E】情人节的电灯泡(二维树状数组单点更新+区间查询)

试题链接:https://www.nowcoder.com/acm/contest/77/E 题目描述 情人节到了,小芳和小明手牵手,打算过一个完美的情人节,但是小刚偏偏也来了,当了一个明晃晃的电灯泡,小明很尴尬,就和小刚说,我交给你个任务,你完成了我俩就带你玩,否则你就回家吧.小刚很有当单身狗的觉悟,他坚决不想让小明过好情人节,同为单身狗的你能帮帮他吗?现在有一个n×n(1 <= n <= 1000)的格子,每一个格子都有一个电灯泡,可能是亮的,也可能是灭的(1代表亮, 0代表灭),现在有两

CSUST 2012 一个顶俩 (本校OJ题)(思维+树链剖分)

(点击这里查看原题,不保证可以进去....外网可能比较卡) Description A:一心一意 B:一个顶俩 最近QQ更新后那个成语接龙好像挺火的?但我只知道图论里一条边是一个顶俩个点的emm. 如果我给你一个n个点n-1条边的无向联通图,但是这里头有一些边是脆弱的.随时都面临崩坏的危险. 为了维持他们的连通性,善良的我又给了你m条紫水晶备用边(u,v).我这里准备Q个问题,第i个问题为一个整数z(1≤z≤n−1)表示若第z条边崩坏了,你能选出多少条备用边保证图继续保持联通. Input 第一

poj 2763 树链剖分(单点更新,区间求值)

http://poj.org/problem?id=2763 Description After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional ro