splay

Box HDU - 2475 (Splay 维护森林)

痞子三分冷 提交于 2019-12-01 17:35:00
Box \[ Time Limit: 5000 ms \quad Memory Limit: 32768 kB \] 题意 给出 \(n\) 个箱子的包含关系,每次两种操作。 操作 \(1\) :把 \(x\) 的箱子及里面的箱子一块挪到 \(y\) 箱子里面去。 操作 \(2\) :查询 \(x\) 箱子的最外层的箱子编号。 思路 对于每一大块箱子,可以看成树和子树的包含关系,那么可以根据树的 \(dfs\) 序,把一个箱子所包含的箱子拍成一个区间,这样就变成了很多颗树。为了方便后面的操作,对于每个箱子 \(x\) 所包含的区间,用标号 \(x\) 来表示开始的位置, \(x+n\) 来表示结束的位置。 使用 \(splay\) 维护每多颗树的 \(dfs\) 序。由于每棵树都有一个自己的 \(root\) 节点,我们让他们的 \(root\) 节点统一连向 \(0\) 这个虚点。 再来看一看操作,操作 \(1\) 可以变成删除操作以及区间移动操作。操作 \(2\) 就是普通的查询操作。 对于操作 \(1\) ,先找到 \(x\) 和 \(x+n\) 所在的位置,把 \(x\) \(splay\) 到其树的 \(root\) 上,把 \(x+n\) \(slay\) 到 \(x\) 的右子树上,那么我们要转移的树就是 \(x->x+n->x+n\) 的所有左子树。 同样的

Link Cut Tree

荒凉一梦 提交于 2019-12-01 08:56:14
Link Cut Tree LCT专题总结 Part 1 LCT 原理介绍 (以下均为个人见解) LCT是一种树链剖分,奇怪的树链剖分 根据我的认知,LCT是基于将整颗树随机地剖成若干条能够动态改变的链,每条链均是一条到达祖先的路径 整棵LCT就是由这样的链构成,并且这些链可以动态重构和连接 LCT最核心的操作就是 \(Access\) 如何理解这个操作呢? \(Access(x)\) 就是构造出一条 \(x\) 到根的路径构成的链,并且构造完成后链上没有 \(x\) 的儿子 算法实现起来就是: 切掉 \(x\) 的儿子 \(while\) \(x\) 所在链的顶端不是 \(root\) ​ 切掉 \(fa[top[x]\) ]的儿子 ​ 将 \(x\) 所在的链接在 \(fa[top[x]]\) 下面 我们亲爱的 \(tarjan\) 老先生 证明了这个复杂度是 \(log(n)\) 的 那如何搞定这个断链接链的操作呢? 让 \(Splay\) 来搞定就行了 这样,我们的 \(LCT\) 算法,就是将原来的树,剖成了若干条链,每条链由一棵 \(Splay\) 维护,按照深度构树 Part 2 LCT基本操作 说的轻巧,写起来还是贼** 首先我么考虑存储 通常我们使用的 \(LCT\) 写法都是讲 \(Splay\) 里的 \(fa\) 数组和链与链之间的 \(fa\)

Splay板子

风格不统一 提交于 2019-12-01 07:28:18
参考: Splay详解 1.插入xx数 2.删除xx数(若有多个相同的数,因只删除一个) 3.查询xx数的排名(排名定义为比当前数小的数的个数+1+1。若有多个相同的数,因输出最小的排名) 4.查询排名为xx的数 5.求xx的前驱(前驱定义为小于xx,且最大的数) 6.求xx的后继(后继定义为大于xx,且最小的数) #include <bits/stdc++.h> #define inf 1000000005 const int N = 100005; using namespace std; inline int read() { register int x=0,f=1;register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } inline void write(register int x) { if(!x)putchar('0');if(x<0)x=-x,putchar('-'); static int sta[36];int tot=0; while(x)sta[tot++]=x%10,x/=10; while(tot

BZOJ4817 [SDOI2017]树点涂色

被刻印的时光 ゝ 提交于 2019-12-01 05:14:36
Bob有一棵$n$个点的有根树,其中$1$号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。 Bob可能会进行这几种操作: 1 x 把点$x$到根节点的路径上所有的点染上一种没有用过的新颜色。 2 x y 求$x$到$y$的路径的权值。 3 x 在以$x$为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。 Bob一共会进行$m$次操作。 $n,m leqslant 10^5$。 题解 这道题我是按着LCT的标签找的,然而看到这道题的时候满脑子都是树剖……根本看不出哪里要用LCT……个人觉得这题还是蛮巧妙的。 首先,如果我们把同一种颜色的点放到LCT的一棵Splay中去,那么可以发现,1操作恰好就是LCT的 access 操作了。 对于一个点,他到根节点的权值,也就是LCT中这个点到根节点的实链的条数。记$f[i]$表示$i$号节点到根的权值。由这个权值的性质,我们不难得到,对于两个点$x$与$y$,$x$到$y$的路径上的权值为$$f[x]+f[y]-2f[lca(x,y)]+1$$ 于是第二个操作也解决了。 第三个操作,我们不难想到把dfs序抽出来,在线段树上查询即可。 最后我们还有一个问题,也就是$f$数组该如何维护。其实不难想到,在 access

BZOJ4817 [SDOI2017]树点涂色

六眼飞鱼酱① 提交于 2019-12-01 05:05:34
Bob有一棵$n$个点的有根树,其中$1$号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。 Bob可能会进行这几种操作: 1 x 把点$x$到根节点的路径上所有的点染上一种没有用过的新颜色。 2 x y 求$x$到$y$的路径的权值。 3 x 在以$x$为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。 Bob一共会进行$m$次操作。 $n,m leqslant 10^5$。 题解 这道题我是按着LCT的标签找的,然而看到这道题的时候满脑子都是树剖……根本看不出哪里要用LCT……个人觉得这题还是蛮巧妙的。 首先,如果我们把同一种颜色的点放到LCT的一棵Splay中去,那么可以发现,1操作恰好就是LCT的 access 操作了。 对于一个点,他到根节点的权值,也就是LCT中这个点到根节点的实链的条数。记$f[i]$表示$i$号节点到根的权值。由这个权值的性质,我们不难得到,对于两个点$x$与$y$,$x$到$y$的路径上的权值为$$f[x]+f[y]-2f[lca(x,y)]+1$$ 于是第二个操作也解决了。 第三个操作,我们不难想到把dfs序抽出来,在线段树上查询即可。 最后我们还有一个问题,也就是$f$数组该如何维护。其实不难想到,在 access

洛谷P2343 宝石管理系统 splay

浪尽此生 提交于 2019-11-30 22:24:47
网址: https://www.luogu.org/problem/P2343 题意: 维护一个支持$O(logn)$插入和查询第$k$大的数据结构。 题解: 只要是平衡树都行。这里我们使用splay,抄个板子即可。 AC代码: #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; struct Splay { int fa[MAXN], val[MAXN], son[MAXN][2], size[MAXN], num[MAXN]; int sz, rt; void init() { rt = sz = 0; } bool getson(int x) { return son[fa[x]][1] == x; } void con(int x, int y, int z) { if (x) fa[x] = y; if (y) son[y][z] = x; } void up(int x) { if (x) { size[x] = num[x]; if (son[x][0]) size[x] += size[son[x][0]]; if (son[x][1]) size[x] += size[son[x][1]]; } } void rotate(int x) { int fx = fa[x],

洛谷P3165 排序机械臂 splay

橙三吉。 提交于 2019-11-30 22:17:22
网址: https://www.luogu.org/problem/P3165 题意: 每一次先输出$pos_i$翻转$[i,pos_i]$,$pos_i$为$i$在当前序列上的位置。 题解: $splay$维护序列。原理是维护中序遍历,具有的性质是$splay$的节点编号一一对应序列上的各个位置的关键字,由于本题中,高度会有相同值,所以以序列的位置为关键字,该关键字和$splay$上的节点编号一一对应建立双射。然后$pos_i$就可以直接找到其在$splay$上的节点编号,把该编号旋到根,就可以求出其权值,然后打翻转标记即可。 AC代码: #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; struct node { int val, pos; node() {}; node(int _val, int _pos) :val(_val), pos(_pos) {}; }; node a[MAXN]; bool cmp(node& a, node& b) { return a.val < b.val || (a.val == b.val && a.pos < b.pos); } int hs[MAXN]; struct Splay { int fa[MAXN], son[MAXN][2],

学习LCT小结

戏子无情 提交于 2019-11-30 15:11:15
前前言 话说前面部分大概是我一年前搞的吧。 最近又复习了一哈LCT,那就补补坑吧。 注意,为了区分,从我写spaly开始都是现在写的。 前言 首先,LCT是什么呢? 我们看看百度百科—— LCT即自动细胞学检测系统,又称液基细胞学检测系统。是宫颈筛查的一种方法。 疏松结缔组织(loose connective tissue)又称蜂窝组织(areolar tissue),其特点是细胞种类较多,纤维较少,排列稀疏。疏松结缔组织在体内广泛分布,位于器官之间、组织之间以至细胞之间,起连接、支持、营养、防御、保护和创伤修复等功能。 好吧,不是这个。 LCT即为link-cut-tree 是一种解决动态树的有效利器。 动态树是一类问题,常见的有维护树的连通性,求树上路径的极值等。 然后LCT即为一种用Splay来维护树链剖分的算法,简单理解为“支持删边、加边的动态树链剖分” 前置技能: 树链剖分https://blog.csdn.net/HiChocolate/article/details/77170675 (不会的可以看看我写的) Splay https://blog.csdn.net/qq_30974369/article/details/77587168 (不会的可以看看不是我写的) 重点是树链剖分的全部内容加上splay的一些基本操作(如标记下传、区间翻转《排序机械臂》) 一些定义

BZOJ4530 [BJOI2014] 大融合

牧云@^-^@ 提交于 2019-11-30 12:55:19
LCT维护子树信息( 考虑维护两个值,一个虚子树信息,一个全部信息。 因为虚子树只有在link和access的时候改变,可以方便的维护。 具体可以康康代码。 近期考虑写点大代码题练练手。 //Love and Freedom. #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define ll long long #define inf 20021225 #define fa(x) t[x].fa #define ls(x) t[x].son[0] #define rs(x) t[x].son[1] #define nrt(x) (ls(fa(x))==x||rs(fa(x))==x) #define N 100010 using namespace std; int read() { int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } struct node{int cnt,sum,fa,son[2]; bool tag;}t[N];

模板—Splay

泪湿孤枕 提交于 2019-11-30 09:15:34
#include<iostream> #include<cstring> #include<cstdio> #define LL long long using namespace std; struct Splay { struct node { int ch[2],fa,val,cnt,siz; #define l(x) tr[x].ch[0] #define r(x) tr[x].ch[1] #define fa(x) tr[x].fa #define val(x) tr[x].val #define cnt(x) tr[x].cnt #define siz(x) tr[x].siz }tr[1000010]; int sz,root; void clear(int x){fa(x)=l(x)=r(x)=val(x)=cnt(x)=siz(x)=0;} bool get(int x){return r(fa(x))==x;} int newnode(int x) { sz++;val(sz)=x;cnt(sz)=siz(sz)=1; fa(sz)=l(sz)=r(sz)=0;return sz; } void pushup(int x) { if(!x)return; siz(x)=cnt(x); if(l(x))siz(x)+=siz(l(x)); if(r(x))siz