UOJ #207. 共价大爷游长沙(不用维护子树的LCT)

8 篇文章 0 订阅
8 篇文章 0 订阅

传送门

题目大意:自己看题目吧。。


思路

这题真是机巧。

为每一条路径随机一个权值,记录每条边上的异或值。对于一条删边,将其权值异或到新的路径上,用LCT维护。

判断一条边是否被所有路径经过只用判断异或和是否相等就行了。

中间要用map等小技巧,还是比较简单的,不用维护任何东西。但是难想。第一次写随机数冲突了,srand(num)比较可行。还有就是每次询问之前别忘了splay一下。

还有一种维护子树异或和的做法,这里就不讲了。(这也是基础的操作啊)

推荐去看kekxy的博客。


代码

#include <bits/stdc++.h>
#define maxn 200010
#define M1 998244353
#define M2 1000000007
#define M3 1333333331

using namespace std;

int ID, cnt, n, m, ToT, VAL;
map <long long, int> M;
int X[maxn], Y[maxn], Z[maxn];

struct Tnode{
    Tnode *son[2], *fa;
    int parent, val, add;
    bool rev;
    int Get_d(){return fa->son[1] == this;}
    void Connect(Tnode *now, int d){(son[d] = now)->fa = this;}
    void Down(){
        if(rev){
            swap(son[0], son[1]);
            if(son[0])  son[0]->rev ^= 1;
            if(son[1])  son[1]->rev ^= 1;
            rev = false;
        }
        if(add){
            if(son[0])  son[0]->val ^= add, son[0]->add ^= add;
            if(son[1])  son[1]->val ^= add, son[1]->add ^= add;
            add = 0;
        }
    }
}tree[maxn], *Node[maxn];

Tnode *NewTnode(){
    tree[cnt].fa = tree[cnt].son[0] = tree[cnt].son[1] = NULL;
    tree[cnt].parent = tree[cnt].add = 0;
    tree[cnt].rev = false;
    return tree+cnt++;
}

void Zig(Tnode *now){
    Tnode *last = now->fa;
    int d = now->Get_d();
    if(now->son[!d])  last->Connect(now->son[!d], d);
    else  last->son[d] = NULL;
    if(last->fa)  last->fa->Connect(now, last->Get_d());
    else  now->fa = NULL;
    now->Connect(last, !d);
    now->parent = last->parent;
    last->parent = 0;
}

void Splay(Tnode *now){
    Tnode *last;
    while(now->fa){
        last = now->fa;
        if(last->fa)  last->fa->Down();
        last->Down();  now->Down();
        if(last->fa)  (now->Get_d() ^ last->Get_d()) ? Zig(now) : Zig(last);
        Zig(now);
    }
    if(!now->fa)  now->Down();
}

void Access(int x){

    Splay(Node[x]);
    if(Node[x]->son[1]){
        Node[x]->son[1]->fa = NULL;
        Node[x]->son[1]->parent = x;
        Node[x]->son[1] = NULL;
    }

    int y = Node[x]->parent;
    while(y){
        Splay(Node[y]);
        if(Node[y]->son[1]){
            Node[y]->son[1]->fa = NULL;
            Node[y]->son[1]->parent = y;
            Node[y]->son[1] = NULL;
        }
        Node[y]->Connect(Node[x], 1);
        Node[x]->parent = 0;

        x = y;
        y = Node[x]->parent;
    }
}

void Evert(int x){
    Access(x);
    Splay(Node[x]);
    Node[x]->rev ^= 1;
}

void Link(int x, int y){
    Evert(x);
    Node[x]->parent = y;
}

void Cut(int x, int y){
    Evert(x);
    Access(y);
    Splay(Node[x]);
    Node[x]->son[1]->fa = NULL;
    Node[x]->son[1] = NULL;
}

void Update(int x, int y, int val){
    Evert(x);
    Access(y);
    Splay(Node[x]);
    Node[x]->val ^= val;
    Node[x]->add ^= val;
}

int Query(int x, int y){
    int edge = M[1LL*x*(n-1)+y];
    Splay(Node[edge]);
    return Node[edge]->val;
}

int Get(){
    VAL = (1LL * VAL * M1 + M2) % M3;
    return VAL;
}

int main(){

    scanf("%d", &ID);

    scanf("%d%d", &n, &m);

    for(int i = 1; i <= n; i++)  Node[i] = NewTnode();

    int a, b;
    for(int i = 1; i < n; i++){
        Node[i+n] = NewTnode();
        scanf("%d%d", &a, &b);
        M[1LL*a*(n-1)+b] = M[1LL*b*(n-1)+a] = i + n;
        Link(a, i+n);
        Link(i+n, b);
    }

    int op, u, v;
    for(int i = 1; i <= m; i++){
        scanf("%d", &op);
        if(op == 1){
            scanf("%d%d%d%d", &a, &b, &u, &v);

            int edge = M[1LL*a*(n-1)+b];
            Splay(Node[edge]);
            int val = Node[edge]->val;
            Cut(a, edge);
            Cut(edge, b);

            Node[edge]->fa = Node[edge]->son[0] = Node[edge]->son[1] = NULL;
            Node[edge]->val = Node[edge]->parent = 0;
            Node[edge]->rev = false;

            Link(u, edge);
            Link(edge, v);
            M[1LL*u*(n-1)+v] = M[1LL*v*(n-1)+u] = edge;
            Update(a, b, val);
        }
        else if(op == 2){
            scanf("%d%d", &a, &b);
            int val = Get();
            ToT ^= val;
            Update(a, b, val);
            X[++X[0]] = a;  Y[X[0]] = b;  Z[X[0]] = val;        
        }
        else if(op == 3){
            scanf("%d", &a);
            ToT ^= Z[a];
            Update(X[a], Y[a], Z[a]);
        }
        else{
            scanf("%d%d", &a, &b);
            int res = Query(a, b);
            if(res == ToT)  puts("YES");
            else  puts("NO");
        }
    }

    return 0;
} 

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值