树链剖分-链的剖分(线段树维护边权值的更新)

poj3237

Tree
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 3629   Accepted: 1017

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

题意:给出一颗树以及边权值,对边权有三种操作:(1)把第i条边的权值改成v;(2)把<u,v>路径上的边权值改为原来的相反数;(3)输出<u,v>路径上的最大权值;

程序:

#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 11009
#define eps 1e-10
#define inf 1000000000
#define mod 1000000000
#define INF 1000000000
using namespace std;
struct node
{
    int u,v,w,next;
}edge[M*2];
int t,head[M];
int son[M];//记录重链中某点的儿子节点,子叶节点的儿子为-1;
int fa[M];//记录每个节点的父节点;
int num[M];//记录以该节点为根的子树中有多少个节点;
int top[M];//记录某条重链中所有节点的最初节点编号;
int p[M];//记录某个节点的编号(对原来的节点重新编号)
int fp[M];//记录某编号的节点对应的原来的节点编号;
int deep[M];//记录某个节点在树中的深度;
int a[M];//记录编过号的节点与其父节点之间的边的边权值;维护的线段树是n-1个点
int pos;
int Max;
void init()
{
    t=pos=0;
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
}
void add(int u,int v)
{
    edge[t].u=u;
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
void dfs(int u,int f,int d)
{
    deep[u]=d;
    num[u]=1;
    fa[u]=f;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v!=f)
        {
            dfs(v,u,d+1);
            num[u]+=num[v];
            if(son[u]==-1||num[son[u]]<num[v])
                son[u]=v;
        }
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=pos++;
    fp[p[u]]=u;
    if(son[u]==-1)return;
    getpos(son[u],sp);
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v!=fa[u]&&v!=son[u])
            getpos(v,v);
    }
}//以上是求重链
//***************************以下是线段树操作****************************//
struct Node
{
    int l,r,flag,maxi,mini;
}tree[M*4];
void pushup(int i)
{
    tree[i].maxi=max(tree[i*2].maxi,tree[i*2+1].maxi);
    tree[i].mini=min(tree[i*2].mini,tree[i*2+1].mini);
}
void pushdown(int i)//lazy操作
{
    if(tree[i].l==tree[i].r)return;
    if(tree[i].flag)
    {
        tree[i*2].maxi=-tree[i*2].maxi;
        tree[i*2].mini=-tree[i*2].mini;
        swap(tree[i*2].maxi,tree[i*2].mini);
        tree[i*2].flag^=1;
        tree[i*2+1].maxi=-tree[i*2+1].maxi;
        tree[i*2+1].mini=-tree[i*2+1].mini;
        swap(tree[i*2+1].maxi,tree[i*2+1].mini);
        tree[i*2+1].flag^=1;
        tree[i].flag=0;
    }
}
void make(int l,int r,int i)//建立线段树
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].flag=0;
    if(tree[i].l==tree[i].r)
    {
        tree[i].maxi=tree[i].mini=a[tree[i].l];
        return;
    }
    int mid=(l+r)>>1;
    make(l,mid,i*2);
    make(mid+1,r,i*2+1);
    pushup(i);
}
void change(int p,int q,int i)//单点更新
{
    if(tree[i].l==p&&tree[i].r==p)
    {
        tree[i].maxi=tree[i].mini=q;
        tree[i].flag=0;
        return;
    }
    pushdown(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(p<=mid)change(p,q,i*2);
    else change(p,q,i*2+1);
    pushup(i);
}
void negval(int l,int r,int i)//区间修改为相反数
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        tree[i].maxi=-tree[i].maxi;
        tree[i].mini=-tree[i].mini;
        swap(tree[i].maxi,tree[i].mini);
        tree[i].flag^=1;
        return;
    }
    pushdown(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        negval(l,r,i*2);
    else if(l>mid)
        negval(l,r,i*2+1);
    else
    {
        negval(l,mid,i*2);
        negval(mid+1,r,i*2+1);
    }
    pushup(i);
}
void query(int l,int r,int i)//区间查找
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        Max=max(Max,tree[i].maxi);
        return;
    }
    pushdown(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        query(l,r,i*2);
    else if(l>mid)
        query(l,r,i*2+1);
    else
    {
        query(l,mid,i*2);
        query(mid+1,r,i*2+1);
    }
    pushup(i);
}
int findmax(int u,int v)//树形图转换为线段树结构,并查找最大值
{
    int f1=top[u];
    int f2=top[v];
    int ans=-inf;
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        Max=-inf;
        query(p[f1],p[u],1);
        ans=max(ans,Max);
        u=fa[f1];
        f1=top[u];
    }
    if(v==u)return ans;
    if(deep[u]>deep[v])swap(u,v);
    Max=-inf;
    query(p[son[u]],p[v],1);
    ans=max(ans,Max);
    return ans;
}
void neg(int u,int v)//树形图转换为线段树结构,并修改区间值
{
    int f1=top[u];
    int f2=top[v];
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        negval(p[f1],p[u],1);
        u=fa[f1];
        f1=top[u];
    }
    if(v==u)return;
    if(deep[u]>deep[v])swap(u,v);
    negval(p[son[u]],p[v],1);
    return;
}
struct Edge
{
    int u,v,w;
}e[M];
int main()
{
    int T,i,n;
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        init();
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            add(e[i].u,e[i].v);
            add(e[i].v,e[i].u);
        }
        dfs(1,1,0);
        getpos(1,1);
        for(i=1;i<n;i++)
        {
            if(deep[e[i].u]<deep[e[i].v])
                swap(e[i].v,e[i].u);
            a[p[e[i].u]]=e[i].w;
        }
        make(1,pos-1,1);
        char ch[22];
        int x,y;
        while(scanf("%s",ch),strcmp(ch,"DONE")!=0)
        {
            scanf("%d%d",&x,&y);
            if(ch[0]=='Q')
            {
                printf("%d\n",findmax(x,y));
            }
            else if(ch[0]=='C')
            {
                change(p[e[x].u],y,1);
            }
            else
                neg(x,y);
        }
    }
    return 0;
}


你可能感兴趣的:(线段树)