zoukankan      html  css  js  c++  java
  • POJ3237 Tree(树链剖分 边权)

    题目大意:
    指定一颗树上有3个操作:
    询问操作,询问a点和b点之间的路径上最长的那条边的长度;
    取反操作,将a点和b点之间的路径权值都取相反数;
    变化操作,把某条边的权值变成指定的值。
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstdio>
    using namespace std;
    const int N=100010;
    struct Edge
    {
        int to,next;
    }eg[N*2];
    int head[N],tot;
    int top[N];//top[v]表示v所在的重链的顶端节点
    int fa[N];//父亲节点
    int deep[N];//深度
    int num[N];//num[v]表示以v为根的子树的节点数
    int p[N];//p[v]表示v与其父亲节点的连边在线段树中的位置
    int fp[N];//和p数组相反
    int son[N];//重儿子
    int pos;
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
        pos=0;
        memset(son,-1,sizeof(son));
    }
    void add(int u,int v)
    {
        eg[tot].to=v;
        eg[tot].next=head[u];
        head[u]=tot++;
    }
    void dfs1(int u,int pre,int d)//第一遍dfs求出fa,deep,num,son
    {
        deep[u]=d;
        fa[u]=pre;
        num[u]=1;
        for(int i=head[u];i!=-1;i=eg[i].next)
        {
            int v=eg[i].to;
            if(v!=pre)
            {
                dfs1(v,u,d+1);
                num[u]+=num[v];
                if(son[u]==-1||num[v]>num[son[u]]) son[u]=v;
            }
        }
    }
    void getpos(int u,int sp)//第二遍dfs求出top和p
    {
        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=eg[i].next)
        {
            int v=eg[i].to;
            if(v!=son[u]&&v!=fa[u]) getpos(v,v);
        }
    }
    //线段树
    struct Node
    {
        int l,r,ma,mi,ne;
    }tree[N*3];
    void build(int i,int l,int r)
    {
        tree[i].l=l;
        tree[i].r=r;
        tree[i].ma=tree[i].mi=tree[i].ne=0;
        if(l==r) return ;
        int mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
    }
    void pushup(int i)
    {
        tree[i].mi=min(tree[i<<1].mi,tree[i<<1|1].mi);
        tree[i].ma=max(tree[i<<1].ma,tree[i<<1|1].ma);
    }
    void pushdown(int i)
    {
        if(tree[i].l==tree[i].r) return ;
        if(tree[i].ne)
        {
            tree[i<<1].ma=-tree[i<<1].ma;
            tree[i<<1].mi=-tree[i<<1].mi;
            swap(tree[i<<1].ma,tree[i<<1].mi);
            tree[i<<1|1].ma=-tree[i<<1|1].ma;
            tree[i<<1|1].mi=-tree[i<<1|1].mi;
            swap(tree[i<<1|1].ma,tree[i<<1|1].mi);
            tree[i<<1].ne^=1;
            tree[i<<1|1].ne^=1;
            tree[i].ne=0;
        }
    }
    void update(int i,int k,int val)//更新线段树的第k个值为val
    {
        if(tree[i].l==k&&tree[i].r==k)
        {
            tree[i].ma=tree[i].mi=val;
            tree[i].ne=0;
            return ;
        }
        pushdown(i);
        int mid=(tree[i].l+tree[i].r)>>1;
        if(k<=mid) update(i<<1,k,val);
        else update(i<<1|1,k,val);
        pushup(i);
    }
    void ne_update(int i,int l,int r)//更新线段树的区间[l,r]取反
    {
        if(tree[i].l==l&&tree[i].r==r)
        {
            tree[i].ma=-tree[i].ma;
            tree[i].mi=-tree[i].mi;
            swap(tree[i].ma,tree[i].mi);
            tree[i].ne^=1;
            return ;
        }
        pushdown(i);
        int mid=(tree[i].l+tree[i].r)>>1;
        if(r<=mid) ne_update(i<<1,l,r);
        else if(l>mid) ne_update(i<<1|1,l,r);
        else
        {
            ne_update(i<<1,l,mid);
            ne_update(i<<1|1,mid+1,r);
        }
        pushup(i);
    }
    int query(int i,int l,int r)//查询线段树中[l,r]的最大值
    {
        if(tree[i].l==l&&tree[i].r==r) return tree[i].ma;
        pushdown(i);
        int mid=(tree[i].l+tree[i].r)>>1;
        if(r<=mid) return query(i<<1,l,r);
        else if(l>mid) return query(i<<1|1,l,r);
        else return max(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
        pushup(i);
    }
    int find(int u,int v)//查询u->v边的最大值
    {
        int f1=top[u],f2=top[v],tmp=-100000000;
        while(f1!=f2)
        {
            if(deep[f1]<deep[f2])
            {
                swap(f1,f2);
                swap(u,v);
            }
            tmp=max(tmp,query(1,p[f1],p[u]));
            u=fa[f1];
            f1=top[u];
        }
        if(u==v) return tmp;
        if(deep[u]>deep[v]) swap(u,v);
        return max(tmp,query(1,p[son[u]],p[v]));
    }
    void nega(int u,int v)//把u-v路径上的边的值都设置为val
    {
        int f1=top[u],f2=top[v];
        while(f1!=f2)
        {
            if(deep[f1]<deep[f2])
            {
                swap(f1,f2);
                swap(u,v);
            }
            ne_update(1,p[f1],p[u]);
            u=fa[f1];
            f1=top[u];
        }
        if(u==v) return ;
        if(deep[u]>deep[v]) swap(u,v);
        return ne_update(1,p[son[u]],p[v]);
    }
    int e[N][3];
    int main()
    {
        //freopen("in.txt","r",stdin);
        int t,n;
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d",&n);
            for(int i=0;i<n-1;i++)
            {
                scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
                add(e[i][0],e[i][1]);
                add(e[i][1],e[i][0]);
            }
            dfs1(1,0,0);
            getpos(1,1);
            build(1,0,pos-1);
            for(int i=0;i<n-1;i++)
            {
                if(deep[e[i][0]]>deep[e[i][1]]) swap(e[i][0],e[i][1]);
                update(1,p[e[i][1]],e[i][2]);
            }
            char op[10];
            int u,v;
            while(scanf("%s",op))
            {
                if(op[0]=='D') break;
                scanf("%d%d",&u,&v);
                if(op[0]=='Q') printf("%d
    ",find(u,v));//查询u->v路径上边权的最大值
                else if(op[0]=='N') nega(u,v);
                else update(1,p[e[u-1][1]],v);//修改第u条边的长度为v
            }
        }
        return 0;
    }
  • 相关阅读:
    欧拉公式
    isap的一些想法
    错误合集
    Hello World
    PAT (Advanced Level) Practice 1068 Find More Coins
    PAT (Advanced Level) 1087 All Roads Lead to Rome
    PAT (Advanced Level) 1075 PAT Judge
    PAT (Advanced Level) 1067 Sort with Swap(0, i)
    PAT (Advanced Level) 1017 Queueing at Bank
    PAT (Advanced Level) 1025 PAT Ranking
  • 原文地址:https://www.cnblogs.com/d-e-v-i-l/p/5027340.html
Copyright © 2011-2022 走看看