• luoguP3690 【模板】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

    分析:
    lct,练板子
    以前不知道为什么没A掉,这次一A

    tip

    在expose的时候,一定要在splay之后udate

    link操作只有两句:makeroot和赋值

    非偏爱儿子认爸爸,但爸爸不认这个儿子
    所以在link的时候只改pre

    我觉得最容易写错的地方就是expose

    一定是 while (bh)

    这里写图片描述

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    using namespace std;
    
    const int N=300010;
    int sum[N],v[N],pre[N],ch[N][2];
    int q[N],n,m;
    bool rev[N];
    
    int get(int bh)
    {
        return ch[pre[bh]][0]==bh ? 0:1;
    }
    
    int isroot(int bh)
    {
        return ch[pre[bh]][0]!=bh&&ch[pre[bh]][1]!=bh;
    }
    
    void update(int bh)   //xor
    {
        sum[bh]=v[bh];
        if (ch[bh][0]) sum[bh]^=sum[ch[bh][0]];
        if (ch[bh][1]) sum[bh]^=sum[ch[bh][1]];
    }
    
    void push(int bh)
    {
        if (bh&&rev[bh])
        {
            rev[bh]^=1;
            if (ch[bh][0]) rev[ch[bh][0]]^=1;
            if (ch[bh][1]) rev[ch[bh][1]]^=1;
            swap(ch[bh][0],ch[bh][1]);
        }
    }
    
    void rotate(int bh)
    {
        int fa=pre[bh];
        int grand=pre[fa];
        int wh=get(bh);
        if (!isroot(fa)) ch[grand][ch[grand][0]==fa ? 0:1]=bh;
        ch[fa][wh]=ch[bh][wh^1];
        pre[ch[fa][wh]]=fa;
        ch[bh][wh^1]=fa;
        pre[fa]=bh;
        pre[bh]=grand;
        update(fa);
        update(bh);
    }
    
    void splay(int bh)
    {
        int top=0;
        q[++top]=bh;
        for (int i=bh;!isroot(i);i=pre[i])
            q[++top]=pre[i];
        while (top) push(q[top--]);
        for (int fa;!isroot(bh);rotate(bh))
            if (!isroot(fa=pre[bh]))
                rotate(get(bh)==get(fa)? fa:bh);
    }
    
    void expose(int bh)
    {
        int t=0;
        while (bh)   ///
        {
            splay(bh);
            ch[bh][1]=t;
            update(bh);    //////
            t=bh;
            bh=pre[bh];
        }
    }
    
    void makeroot(int bh)
    {
        expose(bh);
        splay(bh);
        rev[bh]^=1;
    }
    
    void link(int x,int y)   ///
    {
        makeroot(x);
        pre[x]=y;
    }
    
    void cut(int x,int y)
    {
        makeroot(x);
        expose(y);
        splay(y);
        ch[y][0]=pre[x]=0;
    }
    
    int find(int x)
    {
        expose(x);
        splay(x);
        while (ch[x][0]) x=ch[x][0];
        return x;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&v[i]),sum[i]=v[i];
        for (int i=1;i<=m;i++)
        {
            int opt,x,y;
            scanf("%d%d%d",&opt,&x,&y);
            if (opt==1)
            {
                if (find(x)!=find(y)) link(x,y);
            }
            else if (opt==2)
            {
                if (find(x)==find(y)) cut(x,y);
            }
            else if (opt==3)
            {
                makeroot(x);
                v[x]=y;
                update(x);
            }
            else
            {
                makeroot(x);
                expose(y);
                splay(y);
                printf("%d
    ",sum[y]);
            }
        }
        return 0;
    }
  • 相关阅读:
    在opencv3中实现机器学习之:利用正态贝叶斯分类
    在opencv3中进行图片人脸检测
    在opencv3中利用SVM进行图像目标检测和分类
    在opencv3中实现机器学习之:利用svm(支持向量机)分类
    在matlab和opencv中分别实现稀疏表示
    opencv2学习:计算协方差矩阵
    用python简单处理图片(3):添加水印
    Google protocol buffer在windows下的编译
    GEOS库学习之五:与GDAL/OGR结合使用
    GEOS库学习之四:几何关系判断
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673211.html
Copyright © 2020-2023  润新知