• BZOJ 2157 旅游(动态树)


    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2157

    【题目大意】

      支持修改边,链上查询最大值最小值总和,以及链上求相反数

    【题解】

      我们将边转化成点,直接用LCT可以处理以上操作

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring> 
    using namespace std;
    const int N=200010;
    int n;
    const int INF=~0U>>1;
    namespace Link_Cut_Tree{
        int f[N],son[N][2],tmp[N],tag[N],val[N],sum[N],mx[N],mn[N]; 
        bool rev[N];
        void Initialize(){
            memset(f,0,sizeof(f));
            memset(son,0,sizeof(son));
            memset(val,0,sizeof(val));
            memset(rev,0,sizeof(rev));
            memset(sum,0,sizeof(sum));
            memset(tag,0,sizeof(tag)); 
        } 
        void reverse(int x){
            sum[x]=-sum[x];
            val[x]=-val[x];
            swap(mn[x],mx[x]);
            mn[x]=-mn[x],mx[x]=-mx[x];
            tag[x]^=1;
        }
        bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
        void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
        void pb(int x){
            if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;
            if(tag[x]){
                tag[x]=0;
                if(son[x][0])reverse(son[x][0]);
                if(son[x][1])reverse(son[x][1]);
            }
        }
        void up(int x){
            sum[x]=val[x]+sum[son[x][0]]+sum[son[x][1]];
            mx[x]=max(mx[son[x][0]],mx[son[x][1]]);
            mn[x]=min(mn[son[x][0]],mn[son[x][1]]);
            if(x>n)mx[x]=max(mx[x],val[x]);
            if(x>n)mn[x]=min(mn[x],val[x]);
        }
        void rotate(int x){
            int y=f[x],w=son[y][1]==x;
            son[y][w]=son[x][w^1];
            if(son[x][w^1])f[son[x][w^1]]=y;
            if(f[y]){
                int z=f[y];
                if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
            }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
        }
        void splay(int x){
            int s=1,i=x,y;tmp[1]=i;
            while(!isroot(i))tmp[++s]=i=f[i];
            while(s)pb(tmp[s--]);
            while(!isroot(x)){
                y=f[x]; 
                if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
                rotate(x);
            }up(x);
        }
        void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
        // 查询x所在的树的根
        int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
        // 使x成为根
        void makeroot(int x){access(x);splay(x);rev1(x);}
        // 将x和y所属树合并
        void link(int x,int y){makeroot(x);f[x]=y;access(x);}
        // 提取链
        void split(int x,int y){makeroot(y);access(x);splay(x);}
        // 查询x到y的链和
        int ask(int x,int y){split(x,y);return sum[x];}
        // 查询x到y的链最大值
        int askmx(int x,int y){split(x,y);return mx[x];}
        // 查询x到y的链最小值
        int askmn(int x,int y){split(x,y);return mn[x];}
    }
    int E[N],m;
    int main(){
        scanf("%d",&n);
        using namespace Link_Cut_Tree;
        Initialize();
        for(int i=0;i<=n;i++)mx[i]=-INF,mn[i]=INF;
        int id=n;
        for(int i=1;i<n;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            E[i]=++id;
            link(x+1,id); link(y+1,id);
            val[id]=sum[id]=mx[id]=mn[id]=z;
        }char op[10];
        scanf("%d",&m);
        while(m--){
            scanf("%s",op);
            int x,y;
            scanf("%d%d",&x,&y);
            if(op[0]=='N'){split(x+1,y+1);reverse(x+1);}
            else if(op[0]=='S'){printf("%d
    ",ask(x+1,y+1));}
            else if(op[1]=='I'){printf("%d
    ",askmn(x+1,y+1));}
            else if(op[1]=='A'){printf("%d
    ",askmx(x+1,y+1));}
            else{makeroot(E[x]);val[E[x]]=y;}
        }return 0;
    }
  • 相关阅读:
    Array.sort源码
    Linkedlist源码
    最大公约数 2.7
    腾讯笔试题
    腾讯2014校园招聘笔试题
    指针问题
    JavaScript 日历
    QT 初阶 第二章 创建对话框(查找对话框实例)
    QT 初阶 1.3 节 控件的几何排列
    “项目中的问题”
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2157plus.html
Copyright © 2020-2023  润新知