Poj3237-Tree(树链剖分)

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 a, b 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

题意:给出一棵树,有3种操作,一是修改一条边的边权,二是将两个点之间所有边的边权置为相反数,三是查询两个点之间最大边权。

解析:树链剖分,用线段树维护区间最大值,因为有置相反数这一个操作,我在线段树里加三个变量minv(最小值),maxv(最大值),d(懒惰标记,要进行置相反数操作时乘上-1),
区间置了相反数则最大值变最小值,最小值变最大值。

代码
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
#define tu nod[u]
#define tv nod[v]
#define e tree[id]
#define lson tree[id*2]
#define rson tree[id*2+1]
const int maxn=10005;
const int INF=1e9+7;
int N,pid;
vector<int> G[maxn];
struct edge
{
    int u,v,c;
    edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){}
}E[maxn];
struct node
{
    int top,fa,deep;//top所属树链的顶点,fa父节点,deep深度
    int s,p,son; //s以它为子树的大小,p新编号,son重链所指向的点
}nod[maxn];
void dfs(int u,int fa,int deep)
{
    tu.fa=fa,tu.deep=deep,tu.s=1; //保存父节点,深度,大小为1
    int Size=G[u].size();
    for(int i=0;i<Size;i++)
    {
        int v=G[u][i];
        if(v==fa) continue; //父亲不管
        dfs(v,u,deep+1);
        tu.s+=tv.s; //加上子树大小
        if(tu.son==-1||tv.s>nod[tu.son].s) tu.son=v; //找重链节点
    }
}
void Div(int u,int top)
{
    tu.top=top; //重链顶点
    tu.p=++pid; //重新编号
    if(tu.son!=-1) Div(tu.son,top); //有重链继续往下找
    else return;
    int Size=G[u].size();
    for(int i=0;i<Size;i++)
    {
        int v=G[u][i];
        if(v==tu.fa||v==tu.son) continue;
        Div(v,v);  //新的链
    }
}
struct Tree
{
    int le,ri,minv,maxv,d;
    void Set(){ swap(minv,maxv); minv=-minv; maxv=-maxv; d*=-1; } //交换,并置相反数
}tree[4*maxn];
void pushup(int id)
{
    e.minv=min(lson.minv,rson.minv);  //更新最大值最小值
    e.maxv=max(lson.maxv,rson.maxv);
}
void pushdown(int id){ if(e.d==-1) lson.Set(), rson.Set(), e.d=1; } //延迟更新
void Build_tree(int id,int le,int ri)  //建树
{
    e.le=le,e.ri=ri,e.d=1;
    e.minv=INF,e.maxv=-INF;
    if(le==ri) return;
    int mid=(le+ri)/2;
    Build_tree(id*2,le,mid);
    Build_tree(id*2+1,mid+1,ri);
}
void Update1(int id,int k,int v)   //单点更新
{
    int le=e.le,ri=e.ri;
    if(le==ri){ e.minv=e.maxv=v; return; }
    pushdown(id);
    int mid=(le+ri)/2;
    if(k<=mid) Update1(id*2,k,v);
    else Update1(id*2+1,k,v);
    pushup(id);
}
void Update2(int id,int x,int y)  //成段更新
{
    int le=e.le,ri=e.ri;
    if(x<=le&&ri<=y){ e.Set(); return; }
    pushdown(id);
    int mid=(le+ri)/2;
    if(x<=mid) Update2(id*2,x,y);
    if(y>mid)  Update2(id*2+1,x,y);
    pushup(id);
}
int Query(int id,int x,int y)  //查询
{
    int le=e.le,ri=e.ri;
    if(x<=le&&ri<=y) return e.maxv;
    pushdown(id);
    int mid=(le+ri)/2;
    int ret=-INF;
    if(x<=mid) ret=max(ret,Query(id*2,x,y));
    if(y>mid)  ret=max(ret,Query(id*2+1,x,y));
    return ret;
}
int GetAns(int u,int v)   //查询路径最大边权
{
    int f1=tu.top,f2=tv.top;
    int ret=-INF; 
    while(f1!=f2) //不在同一条链上
    {
        if(nod[f1].deep<nod[f2].deep){ swap(f1,f2); swap(u,v); }
        ret=max(ret,Query(1,nod[f1].p,tu.p));  //查询这条链上的
        u=nod[f1].fa; f1=tu.top;  //跳到父节点去
    }
    if(u==v) return ret;
    if(tu.deep>tv.deep) swap(u,v);
    ret=max(ret,Query(1,nod[tu.son].p,tv.p));
    return ret;
}
void Negate(int u,int v)  //区间置相反数,跟上面同理,查询变成了更新
{
    int f1=tu.top,f2=tv.top;
    while(f1!=f2)
    {
        if(nod[f1].deep<nod[f2].deep){ swap(f1,f2); swap(u,v); }
        Update2(1,nod[f1].p,tu.p);
        u=nod[f1].fa; f1=tu.top;
    }
    if(u==v) return;
    if(tu.deep>tv.deep) swap(u,v);
    Update2(1,nod[tu.son].p,tv.p);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(int i=0;i<=N;i++) G[i].clear(),nod[i].son=-1;
        pid=0;
        for(int i=1;i<N;i++)
        {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            E[i]=edge(u,v,c);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,0,0);
        Div(1,1);
        Build_tree(1,1,pid);
        for(int i=1;i<N;i++)
        {
            edge& t=E[i];
            int& u=t.u;
            int& v=t.v;
            if(tu.deep>tv.deep) swap(u,v);
            Update1(1,tv.p,t.c); //偏向v点
        }
        char op[10];
        while(scanf("%s",op)!=EOF)
        {
            if(op[0]=='D') break;
            int a,b;
            scanf("%d%d",&a,&b);
            if(op[0]=='C') Update1(1,nod[E[a].v].p,b);
            else if(op[0]=='Q') printf("%d\n",GetAns(a,b));
            else Negate(a,b);
        }
    }
    return 0;
}
View Code

 




posted @ 2016-07-31 09:11  wust_ouyangli  阅读(202)  评论(0编辑  收藏  举报