【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维护子树信息了。
需要注意的是,修改点权的时候一定要先make_root,不然会影响到祖先的sum和xu,复杂度就不对了。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
int n,m,id;
const int N =200005;
typedef unsigned long long ll;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}
struct la{int u,v;ll x;}w[3*N];
ll S;
int cnt;
#define ju(x) (ch[fa[x]][1]==x)
#define nrt(x) ((ch[fa[x]][1]==x)||(ch[fa[x]][0]==x))
int fa[N],ch[N][2];
ll val[N],sum[N],xu[N];
bool r[N];
#define lc (ch[x][0])
#define rc (ch[x][1])
void ud(int x){
    sum[x]=sum[lc]^sum[rc]^val[x]^xu[x];
}
inline void rev(int x){swap(lc,rc),r[x]^=1;}
void psdn(int x){
    if(r[x]){
        if(lc)rev(lc);
        if(rc)rev(rc);
        r[x]=0;
    }
}
void push(int x){
    if(nrt(x))push(fa[x]);
    psdn(x);
}
inline void rot(int x){
    int f=fa[x],of=fa[f],dir=ju(x),nt=nrt(f);
    if(ch[x][dir^1])fa[ch[x][dir^1]]=f;
    ch[f][dir]=ch[x][dir^1];
    fa[f]=x,ch[x][dir^1]=f;
    fa[x]=of;
    if(nt)ch[of][ch[of][1]==f]=x;
    ud(f),ud(x);
}
inline void splay(int x){
    push(x);
    for(int f=fa[x];nrt(x);rot(x),f=fa[x])
    if(nrt(f))if(ju(x)^ju(f))rot(x);else rot(f);
}
inline void access(int x){
    for(int y=0;x;x=fa[y=x]){
        splay(x);
        xu[x]^=sum[y];
        xu[x]^=sum[ch[x][1]];
        ch[x][1]=y;
        ud(x);
        //update!
    }
}
inline void make_root(int x){
    access(x),splay(x),rev(x);
}
inline void cut(int x,int y){
    make_root(x),access(y),splay(x);
    ch[x][1]=fa[y]=0;ud(x);
}
inline void link(int x,int y){
    make_root(y),splay(y),make_root(x),splay(x),fa[x]=y;xu[y]^=sum[x];
}
inline void change(int x,ll v){
    make_root(x);splay(x);val[x]^=v;
    ud(x);
}
int main(){
    srand(time(0));
    id=read(),n=read(),m=read();
    int u,v,op,x,y;
    rep(i,2,n)scanf("%d%d",&u,&v),link(u,v);
    while(m--){
        op=read(),u=read();
        if(op==1){
            v=read(),x=read(),y=read();
            cut(u,v),link(x,y);
        }
        else if(op==2){
            v=read();
            w[++cnt]=(la){u,v,(ll)1ll*rand()*rand()};
            change(u,w[cnt].x),change(v,w[cnt].x);
            S^=w[cnt].x;
        }
        else if(op==3){
            x=w[u].u,y=w[u].v;
            change(x,w[u].x),change(y,w[u].x);
            S^=w[u].x;
        }
        else{
            v=read();
            make_root(u),access(v);
            splay(u);
            if(S==sum[v])puts("YES");
            else puts("NO");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Sinuok/p/11126950.html

时间: 2024-08-02 07:16:50

【LCT维护子树信息】uoj207 共价大爷游长沙的相关文章

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

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

[UOJ207]共价大爷游长沙

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

【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息

题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量. 例如,在上图中,现在一共有了5条边.其中,(3,8)这条边的负载是6,因为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8). 现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问. 输入 第一行包含两个整数N,Q,表示星球的

【BZOJ3510】首都 LCT维护子树信息+启发式合并

[BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖.A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路. 同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公

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

bzoj3510 首都 LCT 维护子树信息+树的重心

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删去这个点以后剩下的连通块最大的最小的点为重心. 一棵树最多只能有两个相邻的直径: 一棵树的重心到一棵树中所有点的距离和最小.(这个也是题目的条件转化为重心的原因) 两棵树的并的重心在两棵树各自的重心的连线上. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置. 有了这些性质,我们可以发现,

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

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

UOJ #207. 共价大爷游长沙

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

Loj 2230. 「BJOI2014」大融合 (LCT 维护子树信息)

链接:https://loj.ac/problem/2230 思路: 设立siz数组保存虚点信息,sum表示总信息 维护子树信息link操作和access操作需要进行一些改动 可参考博客:https://www.cnblogs.com/GXZlegend/p/7061458.html 实现代码; #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include&l