zoukankan      html  css  js  c++  java
  • 洛谷 P3690 Link Cut Tree

    题目背景

    动态树

    题目描述

    给定N个点以及每个点的权值,要你处理接下来的M个操作。操作有4种。操作从0到3编号。点从1到N编号。

    0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。

    1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接。

    2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。

    3:后接两个整数(x,y),代表将点X上的权值变成Y。

    输入输出格式

    输入格式:

    第1行两个整数,分别为N和M,代表点数和操作数。

    第2行到第N+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。

    第N+2行到第N+M+1行,每行三个整数,分别代表操作类型和操作所需的量。

    输出格式:

    对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。

    输入输出样例

    输入样例#1: 
    3 3 
    1
    2
    3
    1 1 2
    0 1 2 
    0 1 1
    输出样例#1: 
    3
    1
    

    说明

    数据范围: N,M<=3*10^5.

    课上听老师讲的还蛮有道理的,然而调起来简直想打人hhh

    不能完全按照splay的套路写。。例如以下的这个错误我调了一个点(...):
    我写splay的时候rotate直接判断grandfather(x)如果是0的话就不用连x了,

    但是当LCT这么写(我一开始改的是!isroot(fa),但是此时fa的father已经变了,所以gg)会挂。

    得改成 if(ch[ffa][0]==fa||ch[ffa][1]==fa) then (balabla)

    诸如此类的细节还有很多,,,反正多写写把。。。晚上再搞一道熟练熟练。

    /*  若干splay维护树(森林)中的重链 
        
        每颗splay的中序遍历恰好是一条重链
        从上走到下。 
        
        一个节点最多只能有一个偏爱儿子,
        所以在access的时候要先把当前点旋到splay的根,
        把右儿子(也就是在树中的偏爱儿子)断掉,
        换成到access的点路径上的儿子。
    */
    #include<bits/stdc++.h>
    #define maxn 300005
    using namespace std;
    int n,m,val[maxn],opt,a,b;
    struct LCT{
        int len,ch[maxn][2],f[maxn];
        int tag[maxn],xr[maxn],q[maxn];
        
        inline void init(){
            memset(f,0,sizeof(f));
            memset(ch,0,sizeof(ch));
            memset(tag,0,sizeof(tag));
        }
        
        //更新节点信息 
        inline void update(int x){
            xr[x]=xr[ch[x][0]]^xr[ch[x][1]]^val[x];
        }
        //标记下传 
        inline void pushdown(int x){
            if(tag[x]){
                tag[x]=0,tag[ch[x][0]]^=1,tag[ch[x][1]]^=1;
                swap(ch[x][0],ch[x][1]);
            }
        }
         
        inline int get(int x){
            return ch[f[x]][1]==x;
        }
        //判断一个节点是否为当前splay的根 
        inline bool isroot(int x){
            return (ch[f[x]][0]!=x&&ch[f[x]][1]!=x);
        }
        //splay的旋转操作 
        inline void rotate(int x){
            int fa=f[x],ffa=f[fa],tp=get(x);
            ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa;
            ch[x][tp^1]=fa,f[fa]=x;
            f[x]=ffa;
            if(ch[ffa][0]==fa||ch[ffa][1]==fa) ch[ffa][ch[ffa][1]==fa]=x;
            update(fa),update(x);
        }
        //旋到根 
        inline void splay(int x){
            len=0;
            for(int i=x;;i=f[i]){
                q[++len]=i;
                if(isroot(i)) break;
            } 
            for(;len;len--) pushdown(q[len]);
            
            while(!isroot(x)){
                int y=f[x],z=f[y];
                if(!isroot(y)) rotate((get(y)==get(x)?y:x));
                rotate(x);
            }
            
        }
        //将一个点到它所在的树的根的路径上的边都变成重边 
        inline void access(int x){
            for(int son=0;x;son=x,x=f[x]) splay(x),ch[x][1]=son,update(x);
        }
        //把一个节点搞成它所在树的根 
        inline void makeroot(int x){
            access(x);
            splay(x),tag[x]^=1;
        }
        //找所在树的根
        inline int find_root(int x){
            access(x),splay(x);
            while(ch[x][0]) x=ch[x][0];
            return x;
        }
        //把y所在的树从y点接到x点上 
        inline void add(int x,int y){
            makeroot(x),f[x]=y;
            //不能更新,因为y不是x的重儿子 
        }
        //把x和y点断开
        inline void cut(int x,int y){
            makeroot(x),access(y);
            splay(y);
            if(ch[y][0]==x) ch[y][0]=0,f[x]=0;
        } 
    }M;
    
    int main(){
        M.init(); 
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",val+i),M.xr[i]=val[i];
        while(m--){
            scanf("%d%d%d",&opt,&a,&b);
            if(!opt){
                M.makeroot(a),M.access(b),M.splay(b);
                printf("%d
    ",M.xr[b]);
            }
            else if(opt==1){
                if(M.find_root(a)==M.find_root(b)) continue;
                M.add(a,b);
            }
            else if(opt==2){
                if(M.find_root(a)!=M.find_root(b)) continue;
                M.cut(a,b);
            }
            else{
                M.access(a),M.splay(a);
                val[a]=b,M.update(a);
            }
        }
        
        return 0;
    }
  • 相关阅读:
    NSUserDefaults存储自定义类
    beginBackgroundTaskWithExpirationHandle
    instancetype
    #define const extern
    singleton
    报错:说改变了系统文件。解决方法
    不合法语句 self.contentView.frame.origin.x = x;
    google应用商店的解决
    笔记
    读流testDemo
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8317849.html
Copyright © 2011-2022 走看看