zoukankan      html  css  js  c++  java
  • 树链剖分-链的剖分(线段树维护边权值的更新)

    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
    ",findmax(x,y));
                }
                else if(ch[0]=='C')
                {
                    change(p[e[x].u],y,1);
                }
                else
                    neg(x,y);
            }
        }
        return 0;
    }
    


  • 相关阅读:
    Design and Implementation of the Sun Network File System
    Flash: An Efficient and Portable Web Server
    Java集合框架练习-计算表达式的值
    后缀数组专题训练
    经典问题-生产者和消费者问题
    ubuntu14.04下配置Java环境以及安装最新版本的eclipse
    Java多线程之CountDownLatch学习
    ZooKeerper学习之Watcher
    ZooKeeper之FastLeaderElection算法详解
    python获取当天日期进行格式转换
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348193.html
Copyright © 2011-2022 走看看