UOJ207:共价大爷游长沙

题面

UOJ

Sol

神题
给每个点对随机一个权值,把这两个点的权值异或上这个随机的值
用\(LCT\)维护子树信息,若子树异或和为所有点对的异或和那么就是答案

大常数代码

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1e5 + 5);

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, m, ch[_][2], fa[_], size[_], sum[_], val[_], rev[_], S[_], top, Sum;
struct Edge{
    int u, v, w;
} P[_ << 2];

# define ls ch[x][0]
# define rs ch[x][1]

IL bool Son(RG int x){
    return ch[fa[x]][1] == x;
}

IL bool Isroot(RG int x){
    return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}

IL void Reverse(RG int x){
    if(!x) return;
    rev[x] ^= 1; swap(ls, rs);
}

IL void Pushdown(RG int x){
    if(!rev[x]) return;
    Reverse(ls); Reverse(rs); rev[x] = 0;
}

IL void Update(RG int x){
    sum[x] = val[x] ^ size[x] ^ sum[ls] ^ sum[rs];
}

IL void Rotate(RG int x){
    RG int y = fa[x], z = fa[y], c = Son(x);
    if(!Isroot(y)) ch[z][Son(y)] = x; fa[x] = z;
    ch[y][c] = ch[x][!c]; fa[ch[y][c]] = y;
    ch[x][!c] = y; fa[y] = x;
    Update(y);
}

IL void Splay(RG int x){
    S[top = 1] = x;
    for(RG int y = x; !Isroot(y); y = fa[y]) S[++top] = fa[y];
    while(top) Pushdown(S[top--]);
    for(RG int y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])
        if(!Isroot(y)) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
    Update(x);
}

IL void Access(RG int x){
    for(RG int y = 0; x; y = x, x = fa[x]){
        Splay(x);
        size[x] ^= sum[rs] ^ sum[y];
        rs = y; Update(x);
    }
}

IL void Makeroot(RG int x){
    Access(x); Splay(x); Reverse(x);
}

IL void Link(RG int x, RG int y){
    Makeroot(x); Makeroot(y); fa[x] = y;
    size[y] ^= sum[x]; Update(y);
}

IL void Split(RG int x, RG int y){
    Makeroot(x); Access(y); Splay(y);
}

IL void Cut(RG int x, RG int y){
    Split(x, y); fa[x] = ch[y][0] = 0;
}

# define yyb 141905
# define lrh 141936
# define ni_dong_de +

int main(RG int argc, RG char* argv[]){
    srand(yyb ni_dong_de lrh);
    Input(); n = Input(); m = Input();
    for(RG int i = 1, x, y; i < n; ++i)
        x = Input(), y = Input(), Link(x, y);
    for(RG int i = 1, tot = 0; i <= m; ++i){
        RG int opt = Input(), x = Input(), y, u, v;
        if(opt == 1){
            y = Input(), u = Input(), v = Input();
            Cut(x, y), Link(u, v);
        }
        else if(opt == 2){
            P[++tot].u = x, P[tot].v = y = Input();
            P[tot].w = rand() % 19260817;
            Makeroot(x); val[x] ^= P[tot].w; Update(x);
            Makeroot(y); val[y] ^= P[tot].w; Update(y);
            Sum ^= P[tot].w;
        }
        else if(opt == 3){
            Makeroot(P[x].u); val[P[x].u] ^= P[x].w; Update(P[x].u);
            Makeroot(P[x].v); val[P[x].v] ^= P[x].w; Update(P[x].v);
            Sum ^= P[x].w;
        }
        else{
            y = Input(); Split(x, y);
            if(sum[x] ^ Sum) puts("NO");
            else puts("YES");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cjoieryl/p/8427481.html

时间: 2024-08-28 21:50:56

UOJ207:共价大爷游长沙的相关文章

[uoj207]共价大爷游长沙——lct

题目大意: 给定一棵树和一些路径的集合,同时树和集合都可以支持在线修改,然后在某一时刻求一条边是否被所有集合之中的路径给覆盖. 思路: 考虑一个简单的思路,每当添加一条路径,我们就把在这条路径上的所有边的边权都异或上一个随机值,然后对于任意一条需要询问的边,我们只需要判断它的权值是否等于目前所有的路径的权值的异或和即可. 当我们的权值很大的时候,出错的概率很低,所以可以近似为正确的. 但是树的形态也需要动态修改,这就说明一条路径在不同的版本中,它所代表的边是不一样的,这就很麻烦. 但是仔细观察一

[UOJ207]共价大爷游长沙

如果每次加入点对$(x,y)$,就给它一个随机的权值$v$,把两个点的点权都异或$v$,查询$(x,y)$的时候,只要把$x$硬点为根,以$y$为根的子树的异或和等于当前所有的异或和,那么很大概率就是正确的(每对点刚好有一个在$y$的子树中) 所以直接用lct维护即可,因为维护了虚边信息,所以link时两边都要makeroot(不然没法更新splay里的祖先的信息),cut时不改虚边信息 splay之前一定要记得一路pushdown啊啊啊啊啊啊! #include<stdio.h> #incl

【LCT维护子树信息】uoj207 共价大爷游长沙

这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate,access的时候由儿子update到父亲,而轻儿子的信息update不上来,需要另外记一下. 记sum[x]为我们要求的子树信息,xu[x]为x的轻儿子的子树信息. (即,xu[x]由轻儿子的sum更新,sum[x]由xu[x]和splay子树上的儿子的sum更新. 这样我们就可以完整地用lct维

UOJ #207. 共价大爷游长沙

#207. 共价大爷游长沙 链接:http://uoj.ac/problem/207 题意:给一棵树,要求支持加边.删边.询问一条边是否被所有路径覆盖.同时路径端点集合有加入与删除操作. 想法: 考虑一个点与其父亲边是否被一条路径经过.就是该路径的一端在其子树中,另一端不在.就是其子树中一条路径的端点出现次数为奇数.随机给一条路径两端一个权值(错误概率为$\frac{n^2}{2^w}$),然后如果一个节点子树xor值等于当前路径xor值,其到父亲边就是可行的边. 然后便是LCT维护加边,删边,

@uoj - [email&#160;protected] 共价大爷游长沙

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 火车司机出秦川,跳蚤国王下江南,共价大爷游长沙.每个周末,勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 n 个点 n?1 条边的无向图,点编号为 1 到 n,任意两点间均存在恰好一条路径,显然两个点之间最多也只会有一条边相连.有一个包含一些点对 (x,y) 的可

【uoj207】 共价大爷游长沙

http://uoj.ac/problem/207 (题目链接) 题意 给出一棵无根树,4种操作:在路径集合中加入一条路径,在路径集合中删除一条路径,删一条边加一条边,查询一条边是否被集合中所有路径经过. Solution 将路径端点同时异或上一个值,那么如果一条路径被经过,那么它的子树中点的异或和一定等于所有路径的异或和. 考虑如何用LCT维护这种可加减的子树信息. 对于询问,我们将询问的点access一下,那么它的所有虚儿子就是它在真实的树中的所有儿子了. 对于会使轻重边切换的操作:acce

#207. 共价大爷游长沙

题目描述 http://uoj.ac/problem/207 题解 因为这道题有删边和加边的操作,所以我们不能再链上操作,只能在点上操作. 考虑一些正确性玄学的算法. 我们给每一次链加随机一个权值,这样对于每次询问就查一下这条边分成的两块中的权值异或和是否等于当前所有链的权值异或和即可. 代码 #include<iostream> #include<cstdio> #include<cstdlib> #define ls ch[x][0] #define rs ch[x

总结与心得(持续更新)

不知道为什么,刚学的算法过了2个月就忘得一干二净,我并没有背代码啊,当时学的时候还刷了好多题来着→_→,我是不是大脑能力严重衰退了. 动态规划 单调队列 一般情况下,${dp}$方程可以搞成这样:${f_i=f_j+t_j+t_i}$,只要其中没有变量同时与${i,j}$都有关,那么我们可以用单调队列来做,单调队列里面元素的关键字就是与${j}$有关的东西${f_j+t_j}$.example:生产产品 有些比较特殊的,虽然存在同时与${i,j}$相关的函数,但是这个函数比较简单,使得已经存在在

XJOI网上同步训练DAY2 T2

[问题描述] 火车司机出秦川跳蚤国王下江南共价大爷游长沙.每个周末勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 个点 条边的无向图点编号为 到 任意两点间均存在恰好一条路径显然两个点之间最多也只会有一条边相连.有一个包含一些点对 的可重集合 共价大爷的旅行路线是这样确定的每次他会选择 中的某一对点 并从 出发沿着唯一路径到达 . 小L是共价大爷的脑残粉为了见到共价大爷的尊容小L决定守在这张图的某条边上等待共价大爷的到来.为了保证一定能见到他显然小L必须选择共价大爷一定会经