首页 > 代码库 > BZOJ 2157 旅游(动态树)

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\n",ask(x+1,y+1));}        else if(op[1]==‘I‘){printf("%d\n",askmn(x+1,y+1));}        else if(op[1]==‘A‘){printf("%d\n",askmx(x+1,y+1));}        else{makeroot(E[x]);val[E[x]]=y;}    }return 0;}

BZOJ 2157 旅游(动态树)