zoukankan      html  css  js  c++  java
  • 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
    ",GetAns(a,b));
                else Negate(a,b);
            }
        }
        return 0;
    }
    View Code



  • 相关阅读:
    [网络流24题]飞行员配对方案问题
    bzoj 1571: [Usaco2009 Open]滑雪课
    bzoj 1001: [BeiJing2006]狼抓兔子
    bzoj 1711: [Usaco2007 Open]Dining吃饭
    bzoj 3379: [Usaco2004 Open]Turning in Homework 交作业
    bzoj 1412: [ZJOI2009]狼和羊的故事
    luogu P1345 [USACO5.4]奶牛的电信Telecowmunication
    hdu1512 Monkey King
    [BZOJ2006][NOI2010]超级钢琴(ST表+堆)
    [BZOJ4824][CQOI2017]老C的键盘(树形DP)
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/5722359.html
Copyright © 2011-2022 走看看