poj 3237 树链剖分(区间更新,区间查询)

http://poj.org/problem?id=3237

Description

You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N ? 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions
can be one of the following forms:

CHANGE i v Change the weight of the ith edge to v
NEGATE a b Negate the weight of every edge on the path from a to b
QUERY a b Find the maximum weight of edges on the path from a to b

Input

The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N ? 1 lines each contains three integers ab and c, describing an edge connecting nodes a and bwith
weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

Output

For each “QUERY” instruction, output the result on a separate line.

Sample Input

1

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

Sample Output

1
3
/**
poj 3237 树链剖分(区间更新,区间查询)
题目大意:给定一棵树,动态修改:1.对于给定的两点之间的所有边权取相反数,2对于给定边修改值,动态查询:指定两点间边权最大值
解题思路:树链剖分。在线段树区间维护的时候要维护一个最大值和一个最小值,因为一翻转二者就会相互装换
*/
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int maxn=10005;
int fa[maxn],dep[maxn],son[maxn],d[maxn][3],num[maxn],top[maxn],siz[maxn];
int n,z,maxx[maxn*4],minn[maxn*4],col[maxn*4];
int head[maxn],ip;

void init()
{
    memset(col,0,sizeof(col));
    memset(head,-1,sizeof(head));
    ip=0;
}

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

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);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v])
        {
            son[u]=v;
        }
    }
    ///printf("%d son fa dep %d %d %d\n",u,son[u],fa[u],dep[u]);
}

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

void push_up(int root)
{
    maxx[root]=max(maxx[root<<1],maxx[root<<1|1]);
    minn[root]=min(minn[root<<1],minn[root<<1|1]);
}

void push_down(int root)
{
    if(col[root])
    {
        maxx[root<<1|1]=-maxx[root<<1|1];
        minn[root<<1|1]=-minn[root<<1|1];
        swap(maxx[root<<1|1],minn[root<<1|1]);
        maxx[root<<1]=-maxx[root<<1];
        minn[root<<1]=-minn[root<<1];
        swap(maxx[root<<1],minn[root<<1]);
        col[root<<1]^=1;
        col[root<<1|1]^=1;
        col[root]=0;
    }
}

void update(int root,int l,int r,int loc,int z)
{
    if(l>loc||r<loc)return;
    if(l==r)
    {
        col[root]=0;
        maxx[root]=z;
        minn[root]=z;
        return;
    }
    push_down(root);
    int mid=(l+r)>>1;
    update(root<<1,l,mid,loc,z);
    update(root<<1|1,mid+1,r,loc,z);
    push_up(root);
}

void update1(int root, int l,int r,int x,int y)
{
    if(l>y||r<x)return;
    if(x<=l&&r<=y)
    {
        maxx[root]=-maxx[root];
        minn[root]=-minn[root];
        swap(maxx[root],minn[root]);
        col[root]^=1;
        return;
    }
    push_down(root);
    int mid=(l+r)>>1;
    update1(root<<1,l,mid,x,y);
    update1(root<<1|1,mid+1,r,x,y);
    push_up(root);
}

int query(int root ,int l,int r,int x,int y)
{
    if(l>y||r<x)return -0x3f3f3f3f;
    if(x<=l&&r<=y)
    {
        return maxx[root];
    }
    push_down(root);
    int mid=(l+r)>>1;
    return max(query(root<<1,l,mid,x,y),query(root<<1|1,mid+1,r,x,y));
}
int main()
{
    ///freopen("data.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        for(int i=1; i<n; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            d[i][0]=u,d[i][1]=v,d[i][2]=w;
            addedge(u,v,w);
            addedge(v,u,w);
        }
        int root=(n+1)>>1;
        z=0,siz[0]=0,dep[0]=0;
        dfs(root,0);
        init_que(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 s[10];
            scanf("%s",s);
            if(s[0]=='D')break;
            int x,y;
            scanf("%d%d",&x,&y);
            if(s[0]=='C')
            {
                update(1,1,z,num[d[x][1]],y);
            }
            else if(s[0]=='N')
            {
                int f1=top[x],f2=top[y];
                while(f1!=f2)
                {
                    if(dep[f1]<dep[f2])
                    {
                        swap(f1,f2);
                        swap(x,y);
                    }
                    if(x!=y)
                    {
                        update1(1,1,z,num[f1],num[x]);
                        x=fa[f1],f1=top[x];
                    }
                }
                if(x!=y)
                {
                    if(dep[x]>dep[y])
                    {
                        swap(x,y);
                    }
                    update1(1,1,z,num[son[x]],num[y]);
                }
            }
            else
            {
                int f1=top[x],f2=top[y];
                int sum=-0x3f3f3f3f;
                while(f1!=f2)
                {
                    if(dep[f1]<dep[f2])
                    {
                        swap(f1,f2);
                        swap(x,y);
                    }
                    sum=max(sum,query(1,1,z,num[f1],num[x]));
                    x=fa[f1],f1=top[x];
                }
                if(x!=y)
                {
                    if(dep[x]>dep[y])
                    {
                        swap(x,y);
                    }
                    sum=max(query(1,1,z,num[son[x]],num[y]),sum);
                }
                printf("%d\n",sum);
            }
        }
    }
    return 0;
}

时间: 2024-11-04 14:53:52

poj 3237 树链剖分(区间更新,区间查询)的相关文章

POJ 3237 /// 树链剖分 线段树区间修改(*-1)

题目大意: 给定树的N个结点 编号为1到N 给定N-1条边的边权. 三种操作: CHANGE k w:将第 k 条边的权值改成 w. NEGATE x y:将x到y的路径上所有边的权值乘 -1. QUERY x y:找出x到y的路径上所有边的最大权值. 单点更新 区间更新  区间查询 由于第二个操作是乘 -1 所以需要同时维护最大值和最小值 所以 lazy用来标记是否乘-1 0表示不乘-1 1表示乘-1 http://www.cnblogs.com/HDUjackyan/p/9279777.ht

POJ 3237 树链剖分

点击打开链接 题意:给一个树,三种操作,一个是将第I条边的权值改变,一个是将u到v的所有边的权值取反,一个是询问u到v的路径中边的最大值 思路:和模版的树链剖分没什么区别,这题唯一的坑点就是线段树的懒惰标记,只要有更新操作或者查询操作就都要pushdown(),然后改权值的比较简单,单点更新,而区间取反我们可以用两个数组直接模拟,一个最大值的,一个区间最小值的,然后一旦取反了,就将最大值改为负的最小值,而最小值一样改为负的最大值就可以了 #include <vector> #include &

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

POJ 1195-Mobile phones(二维树状数组-区间更新区间查询)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 17661   Accepted: 8173 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

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]

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

POJ 2763 (树链剖分+边修改+边查询)

题目链接:http://poj.org/problem?id=2763 题目大意:某人初始在s点.有q次移动,每次移动沿着树上一条链,每经过一条边有一定花费,这个花费可以任意修改.问每次移动的花费. 解题思路: 树链剖分基础题.每次Q之后改变一下s. 线段树记录的是边权.方法是对于一条边(u,v),边权值加在dep比较大的那一端. 链查询(边)和 链查询(点)在轻链时略有不同. 注意本题使用vector邻接表存图是会TLE的,应该使用链式前向星.树链剖分中使用链式前向星是基本要求. #inclu

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

bzoj2243树链剖分+区间合并

树链上区间合并的问题比区间修改要复杂,因为每一条重链在线段树上分布一般都是不连续的,所以在进行链上操作时要手动将其合并起来,维护两个端点值 处理时的方向问题:lca->u是一个方向,lca->v是另一个方向,到最后合并这两个放向时都看左端点即可 #include<cstring> #include<string> #include<iostream> #include<queue> #include<cstdio> #include&