• BZOJ3282Tree——LCT


    题目描述

    给定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行,每行三个整数,分别代表操作类型和操作所需的量。
    1<=N,M<=300000

    输出

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

    样例输入

    3 3
    1
    2
    3
    1 1 2
    0 1 2
    0 1 1

    样例输出

    3
    1
     
    LCT模板题,splay维护子树异或和即可。因为cut时不保证边存在,所以注意cut时的判断。
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,m;
    int x,y;
    int opt;
    int v[300010];
    int f[300010];
    int s[300010][2];
    int st[300010];
    int r[300010];
    int sum[300010];
    int get(int rt)
    {
        return rt==s[f[rt]][1];
    }
    void pushup(int rt)
    {
        sum[rt]=v[rt]^sum[s[rt][0]]^sum[s[rt][1]];
    }
    void pushdown(int rt)
    {
        if(r[rt])
        {
            swap(s[rt][0],s[rt][1]);
            r[s[rt][0]]^=1;
            r[s[rt][1]]^=1;
            r[rt]^=1;
        }
    }
    int is_root(int rt)
    {
        return s[f[rt]][0]!=rt&&s[f[rt]][1]!=rt;
    }
    void rotate(int rt)
    {
        int fa=f[rt];
        int anc=f[fa];
        int k=get(rt);
        if(!is_root(fa))
        {
            s[anc][fa==s[anc][1]]=rt;
        }
        s[fa][k]=s[rt][k^1];
        f[s[fa][k]]=fa;
        s[rt][k^1]=fa;
        f[fa]=rt;
        f[rt]=anc;
        pushup(fa);
        pushup(rt);
    }
    void splay(int rt)
    {
        int top=0;
        st[++top]=rt;
        for(int i=rt;!is_root(i);i=f[i])
        {
            st[++top]=f[i];
        }
        for(int i=top;i>=1;i--)
        {
            pushdown(st[i]);
        }
        for(int fa;!is_root(rt);rotate(rt))
        {
            if(!is_root(fa=f[rt]))
            {
                rotate(get(rt)==get(fa)?fa:rt);
            }
        }
    }
    void access(int rt)
    {
        for(int x=0;rt;x=rt,rt=f[rt])
        {
            splay(rt);
            s[rt][1]=x;
            pushup(rt);
        }
    }
    void reverse(int rt)
    {
        access(rt);
        splay(rt);
        r[rt]^=1;
    }
    int find(int rt)
    {
        access(rt);
        splay(rt);
        while(s[rt][0])
        {
            rt=s[rt][0];
        }
        return rt;
    }
    void link(int x,int y)
    {
        reverse(x);
        f[x]=y;
    }
    void cut(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        if(s[x][1]||f[x]!=y||s[y][get(x)^1])
        {
            return ;
        }
        s[y][0]=f[x]=0;
    }
    void change(int rt,int x)
    {
        v[rt]=x;
        access(rt);
        splay(rt);
    }
    int query(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        return sum[y];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
        }
        while(m--)
        {
            scanf("%d%d%d",&opt,&x,&y);
            if(opt==0)
            {
                printf("%d
    ",query(x,y));
            }
            else if(opt==1&&find(x)!=find(y))
            {
                link(x,y);
            }
            else if(opt==2&&find(x)==find(y))
            {
                cut(x,y);
            }
            else if(opt==3)
            {
                change(x,y);
            }
        }
    }
  • 相关阅读:
    for语句及switch case用法示例
    ●验证控件
    ●LinQ to SQL
    ●操作Word
    141107●VS2012的一些使用技巧
    ●Winform拖动无边框窗口、播放音频、启动外部exe程序
    ●操作文件目录及文件
    ●流
    ●事务及异常处理
    ●Winform对话框
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9744724.html
Copyright © 2020-2023  润新知