树链剖分 [POJ 3237] Tree

Tree

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 b with 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

树链剖分模板题、好吧、我又逗比了,最开始初始化为-1,但是由于有负数的存在,所以一直不对、、受不了、总是改不了马虎的习惯

用线段树维护一个最大值和最小值。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <iterator>
#include <cstring>
#include <string>
using namespace std;
#define INF 0x7fffffff
#define ll long long
#define N 100010

struct Edge2
{
    int a,b,c;
}s[N<<1];

struct Edge
{
    int to,next;
}edge[N<<1];
int head[N],tot;

int num[N];
int pos;
int fa[N];
int son[N];
int p[N];
int fp[N];
int deep[N];
int size[N];
int top[N];
int n;

void init()
{
    tot=0;
    pos=1;
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
}
void add(int x,int y)
{
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot++;
}
void dfs1(int now,int pre,int d)
{
    deep[now]=d;
    fa[now]=pre;
    size[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int next=edge[i].to;
        if(next!=pre)
        {
            dfs1(next,now,d+1);
            size[now]+=size[next];
            if(son[now]==-1 || size[next]>size[son[now]])
            {
                son[now]=next;
            }
        }
    }
}
void dfs2(int now,int tp)
{
    top[now]=tp;
    p[now]=pos++;
    fp[p[now]]=now;
    if(son[now]==-1) return;
    dfs2(son[now],tp);
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int next=edge[i].to;
        if(next!=son[now]&&next!=fa[now])
        {
            dfs2(next,next);
        }
    }
}
int mx[N<<2];
int mi[N<<2];
int col[N<<2];
void pushup(int rt)
{
    mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
    mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void pushdown(int rt)
{
    if(col[rt])
    {
        col[rt<<1]^=1;
        col[rt<<1|1]^=1;
        mx[rt<<1]=-mx[rt<<1];
        mi[rt<<1]=-mi[rt<<1];
        swap(mx[rt<<1],mi[rt<<1]);
        mx[rt<<1|1]=-mx[rt<<1|1];
        mi[rt<<1|1]=-mi[rt<<1|1];
        swap(mx[rt<<1|1],mi[rt<<1|1]);
        col[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    col[rt]=0;
    if(l==r)
    {
        mi[rt]=mx[rt]=num[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}
void update(int l,int r,int rt,int pos,int val)
{
    if(l==r)
    {
        mi[rt]=mx[rt]=val;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(pos<=m) update(l,m,rt<<1,pos,val);
    else update(m+1,r,rt<<1|1,pos,val);
    pushup(rt);
}
void update2(int l,int r,int rt,int L,int R)
{
    if(l==L && R==r)
    {
        mx[rt]=-mx[rt];
        mi[rt]=-mi[rt];
        swap(mx[rt],mi[rt]);
        col[rt]^=1;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(R<=m) update2(l,m,rt<<1,L,R);
    else if(L>m) update2(m+1,r,rt<<1|1,L,R);
    else
    {
        update2(l,m,rt<<1,L,m);
        update2(m+1,r,rt<<1|1,m+1,R);
    }
    pushup(rt);
}
int query(int l,int r,int rt,int L,int R)
{
    if(l==L && r==R)
    {
        return mx[rt];
    }
    pushdown(rt);
    int m=(l+r)>>1,ans=-INF;
    if(L>m) return ans=max(ans,query(m+1,r,rt<<1|1,L,R));
    else if(R<=m) ans=max(ans,query(l,m,rt<<1,L,R));
    else return ans=max(ans,max(query(l,m,rt<<1,L,m),query(m+1,r,rt<<1|1,m+1,R)));
    return ans;
}
int convert(int pos)
{
    int a=s[pos].a;
    int b=s[pos].b;
    if(deep[a]>deep[b]) return a;
    return b;
}
void pre_solve()
{
    memset(num,-1,sizeof(num));
    for(int i=1;i<n;i++)
    {
        num[convert(i)]=s[i].c;
    }
}
void change2(int x,int y)
{
    int f1=top[x];
    int f2=top[y];
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(x,y);
            swap(f1,f2);
        }
        update2(1,n,1,p[f1],p[x]);
        x=fa[f1];
        f1=top[x];
    }
    if(x==y) return;
    if(deep[x]>deep[y]) swap(x,y);
    update2(1,n,1,p[x]+1,p[y]);
}
int change(int x,int y)
{
    int ans=-INF;
    int f1=top[x];
    int f2=top[y];
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(x,y);
            swap(f1,f2);
        }
        ans=max(ans,query(1,n,1,p[f1],p[x]));
        x=fa[f1];
        f1=top[x];
    }
    if(x==y) return ans;
    if(deep[x]>deep[y]) swap(x,y);
    ans=max(ans,query(1,n,1,p[x]+1,p[y]));
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
            add(s[i].a,s[i].b);
            add(s[i].b,s[i].a);
        }
        dfs1(1,0,0);
        dfs2(1,1);
        pre_solve();
        build(1,n,1);
        while(1)
        {
            int a,b;
            char op[10];
            scanf("%s",op);
            if(op[0]==‘D‘) break;
            scanf("%d%d",&a,&b);
            if(op[0]==‘C‘)
            {
                a=convert(a);
                update(1,n,1,p[a],b);
            }
            else if(op[0]==‘N‘)
            {
                change2(a,b);
            }
            else
            {
                printf("%d\n",change(a,b));
            }
        }
    }
    return 0;
}
时间: 2024-11-07 22:53:26

树链剖分 [POJ 3237] Tree的相关文章

树链剖分 [HDU 5044] Tree

Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2038    Accepted Submission(s): 391 Problem Description You are given a tree (an acyclic undirected connected graph) with N nodes. The tree

树链剖分 poj 2763

n个点q个查询开始位置s n-1条边 a b  c   a b之间有一条边  权值为c q个查询   0  a  输出现在的位置到 a 所需时间   1  a  b  更新第a条边的权为b #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define MAXN 100010 struct edge { int from,to,w,next; }x[MAXN<

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 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

POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每次更新异或1就可以. 熟悉线段树成段更新就很简单了,最初姿势不对一直wa,还是没有彻底理解lazy标记啊. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace st

poj 3237 Tree 树链剖分+线段树

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

(树链剖分+线段树)POJ - 3237 Tree

前言: 一直听说树链剖分-树链剖分,现在见识一下,,,感觉不是很难0.0 看了一下kuangbin模板基本秒懂 对于点,按重边优先给予每个点一个编号,对于一条重链上的点,编号则是连续的,将所有编号映射到线段树上,即可进行一切区间操作. 对于边的处理,我们将所有边对应到这条边节点更深的那个点上即可. 如果需要的操作只有求和,和单点更新/区间更新,直接用树状数组也是可以的,可能常数大那么一点点. 如果还需要更加强大的操作,显然用splay树维护也是可以的.. 比如树链上所有权值翻转等等..不过,,这

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 instruction

poj 3237 Tree(树链拆分)

题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询ab路径上节点权值的最大值. 解题思路:树链剖分.然后用线段树维护节点权值,成端更新查询. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int max

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b