splay

POJ 3237 Tree

扶醉桌前 提交于 2020-03-28 14:32:12
POJ_3237 用link-cut-tree或者树链剖分都可以,为了处理negate操作,出了lazy标记外可以做两个标记max、min,在执行negate时,令max=-min、min=-max即可。 #include<stdio.h> #include<string.h> #define MAXD 100010 #define MAXM 200010 #define INF 0x7fffffff int N, q[MAXD], first[MAXD], e, next[MAXM], v[MAXM], w[MAXM], dep[MAXD]; struct Edge { int x, y, z; }edge[MAXD]; struct Splay { int pre, ls, rs, neg, key, max, min; bool root; void update(); void pushdown(); void zig(int ); void zag(int ); void splay(int ); void renew() { root = true; pre = ls = rs = 0; neg = 0; } }sp[MAXD]; int Max(int x, int y) { return x > y ? x : y; } int Min(int x, int y)

并不对劲的LCT

断了今生、忘了曾经 提交于 2020-03-25 09:28:09
LCT,是连猫树(link-cat-tree)的缩写。它是树链剖分和splay的结合版本。 由于有很多关于LCT的文章以及这并不是对劲的文章,并不对劲的人并不打算讲得太详细。 推荐:详细的LCT-> 想必大家都知道splay+树剖=LCT splay虽然常数较大,但是它好写好调(大部分操作都可以把左右边界转上去然后直接操作),而且还能维护序列。 树剖是将一棵树切分成很多条链,再将它们首尾相接拼成一个序列。可以用线段树来维护序列,进行区间操作,不过并不能插入和删除。 那么用splay来维护区间是不是就可以插入和删除了呢?想必是可以的。但是插入和删除会导致子树大小有变化,这样轻重链剖分就不适用了。不过,和splay类似地,虽然听上去很玄学,但是期望复杂度是可以被证明为log级别的;和splay类似地,并不对劲的人并不会证明。 讲讲几个操作吧: 1.上/下传标记,判断是左/右儿子 void mark(int u){if(u)swap(ls,rs),re[u]^=1;} void pu(int u){sum[0]=0,sum[u]=sum[ls]^sum[rs]^key[u],sum[0]=0;} void pd(int u){if(re[u])mark(ls),mark(rs),re[u]=0;} int getso(int u){return son[fa[u]][0]==u?0:1;

hyfhaha大事记——luogu

断了今生、忘了曾经 提交于 2020-03-12 05:43:16
成就墙 AK CSP-J 初赛 AK CSP-J 复赛 CSP- J 一等奖 CSP-S 一等奖 大事记 2017-09-20 13:54 注册洛谷账号 之后洛谷一直处于沉沦状态 2018 2018-03-24 过第一道蓝题^_^ 2018-06 开始正式使用洛谷 2018-07-09 暑假开始,通过【模板】并查集,标志着hyfhaha刷题重心转向洛谷。 2018-07 对黄题,绿题有了莫名的喜爱,刷了很多黄和绿。 2018-07-11 通过【模板】线性筛素数,通过人生第一道紫题(恶意评分,我那时候还不知道) 2018-07-12 通过【模板】最小生成树 2018-07-13 通过【模板】字符串哈希,【模板】堆,【模板】三分法 2018-07-18 学会 【floyd】【SPFA】,通过【模板】单源最短路径(弱化版) 2018-07-18 \(\color{green}\text{绿名祭}\) 2018-07-20 大牛祭 2018-07-18~2018-07-23 连续6日 中吉 ,NOI的庇护, RP++ 。 2018-07-26 走上了 数据结构 的不归路 ,通过【模板】线段树1,学会线段树,【模板】树状数组1(线段树过的) 2018-07-26 通过【模板】树状数组2 ,学会树状数组,通过【模板】树状数组1(树状数组过的)。 2018-07-26 通过【模板】快速幂|

Splay 学习笔记

て烟熏妆下的殇ゞ 提交于 2020-03-10 13:27:38
Splay 真的坑人,细节贼多。。。 先日常% foin 神犇。 二叉搜索树(BST) 定义:要么是一棵空树,要么满足以下性质: 若左子树不为空,那么左子树中每一个节点所代表的数都比根节点所代表的数要小。 若右子树不为空,那么右子树中每一个节点所代表的数都比根节点所代表的数要大。 左、右子树均为二叉搜索树。 由于出题人很可能构造毒瘤数据,使 BST 退化为一条链,导致高度过高,所以需要通过 伸展(splay) 来优化运算速度。 怎么存 tot ,表示 BST 中节点数量。 rt ,表示 BST 中的根。 ch[n][2] ,其中 ch[i][0] 代表 i 号节点的左儿子, ch[i][1] 代表 i 号节点的右儿子。 fa[N] ,其中 fa[i] 代表 i 号节点的父亲节点。 val[N] ,其中 val[i] 代表 i 号节点所存储的数。 sz[N] ,其中 sz[i] 代表以 i 号节点为根的子树的大小。 cnt[N] ,其中 cnt[i] 代表 i 号节点代表了几个数。由于可能会多次插入同一个数,所以需要记录每个数出现的次数。 操作 Splay 伸展树需要支持的基本操作有 insert , delete , rank , kth , splay 等。 辅助函数 which(i) 函数代表节点 i 是 fa[i] 的左儿子还是右儿子。这个操作及其简单。 bool which

[平衡树-Splay]营业额统计

喜夏-厌秋 提交于 2020-03-06 00:25:04
题目 https://loj.ac/problem/10143 题解 一眼就能看出这题就是找Splay的前驱和后继 通过这题可以体会到为什么要加入一个无穷小的点和一个无穷大的点,加入可以防止出坑 代码 #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") #include<bits/stdc++.h> using namespace std; #define ll long long const int N = 1e5+7; const int inf = 0x3f3f3f; int rt;//根节点 int tot;//节点个数 struct node { int fa;//父亲节点 int ch[2];//子节点 int val;//权值 int tag;//标记 int sz;//子树大小 int cnt; }s[N]; struct Splay { int get(int x) {return s[s[x].fa].ch[1] == x;} void Clear(int x) { s[x].fa = s[x].ch[0] = s[x].ch[1] = s[x].sz = s[x].val = s[x].tag =0; } void maintain(int x){ s[x].sz = s[s[x]

Link Cut Tree 学习笔记

不羁的心 提交于 2020-03-04 07:47:34
Link Cut Tree 学习笔记 说在前边 最近补 CF 碰见一道 LCT ,就打算学习一下这个东西。。。顺便复习一下 splay。 具体算法及实现 参考了 FlashHu , Candy? P3690 【模板】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。 做法:模板 Code #include <cstdio> #include <algorithm> #include <cstring> #include <cstdlib> #include <cctype> typedef long long ll; const int N = 300010; const int inf = 0x3f3f3f3f; template<class T> inline void read(T &x) { x = 0; char c = getchar(); T f = 1; while(

(转)Splay伸展树模板

允我心安 提交于 2020-03-03 16:03:24
大佬博客: https://www.luogu.com.cn/blog/user19027/solution-p3369 代码: class Splay//存储规则:小左大右,重复节点记录 { #define root e[0].ch[1] //该树的根节点 private: class node { public: int v,father;//节点值,父级节点 int ch[2];//左孩子=0,右孩子=1 int sum;//自己+自己下级有多少节点。在根节点为1。 int recy;//记录自己被重复了几次 }; node e[N];//Splay树主体 int n,points;//使用存储数,元素数 void update(int x) { e[x].sum=e[e[x].ch[0]].sum+e[e[x].ch[1]].sum+e[x].recy; } int identify(int x) { return e[e[x].father].ch[0]==x?0:1; } void connect(int x,int f,int son)//连接函数。用法:connect(son,father,1/0) { e[x].father=f; e[f].ch[son]=x; }//作用:使得x的father=f,f的son=x. void rotate(int x) {

[ZJOI2012]网络(LCT)

…衆ロ難τιáo~ 提交于 2020-03-02 08:11:08
[ZJOI2012]网络(luogu) Solution 对于每个颜色建一棵 LCT 由于两点间至多有一条边,可用 map 维护两点间边的颜色 0 操作把每颗颜色的 LCT 上 x Splay 到 顶点,改颜色 1 操作先依次判断,再断原来的边,连边 2 操作在对应颜色的 LCT 内将 u 至 v 的路径提取出来,输出维护的最大值 Code #include <cstdio> #include <cstdlib> #include <map> #include <algorithm> #define ll long long using namespace std; const int N=1e5+10; int n,m,k,c,u,v,w,col[10010][11],opt; int rev[N],ch[N][2],fa[N],val[N],ma[N],st[N]; map <ll,int> dict; bool nroot(int x) { return x==ch[fa[x]][0]||x==ch[fa[x]][1]; } int get(int x) { return x==ch[fa[x]][1]; } void push_up(int x) { ma[x]=val[x]; if(ch[x][0]) ma[x]=max(ma[x],ma[ch[x][0]]); if

LCT

二次信任 提交于 2020-02-28 07:19:17
原理 懒得讲了 应用 维护链信息 luoguP1501 维护链懒标记的裸题 弹飞绵羊 每个点向右边弹到的点连边,超过 \(n\) 的所有点连向 \(n+1\) ,最后形成一棵树,一个点 \(splay\) 到根后左儿子的数量(深度)就是最后答案 luoguP4332 记录一个节点的权值为 \(0-3\) 表示接受的 \(1\) 状态的数量 考虑每次更改一次节点状态,会自底部向上修改连续一段节点的状态 我们可以平衡树上二分找第一个权值为 \(1/2\) 的节点,也可以直接数组记录,然后把它换到根 注意修改完之后记录 \(1/2\) 的数组要交换,如果这个节点不存在就把整条链都修改 动态维护连通性 luoguP2147 裸题, \(link\) 和 \(cut\) 操作 luoguP2542 常见套路是删边变倒序加边 先将没有被删去的边连起来,我们把每条边中间加一个点,然后把新加的点且在原图中是割点的的点权都变成 \(1\) 倒序操作序列,加边的时候如果两个点不连通就直接连边,让新加的点边权为 \(1\) 否则把那个点到根的权值全部变为 \(0\) 查询操作就是两点间的权值 bzoj2959 \(1\) 操作:连接两个跑道,如果已经联通,那么就把路径上所有点用并查集合并,把所有点的权值给根节点 \(2\) 操作:修改该节点根节点权值 3#操作:求链和 没写,口胡的( 动态维护生成树

SPLAY,LCT学习笔记(六)

99封情书 提交于 2020-02-24 16:27:02
这应该暂时是个终结篇了... 最后在这里讨论LCT的一个常用操作:维护虚子树信息 这也是一个常用操作 下面我们看一下如何来维护 以下内容转自 https://blog.csdn.net/neither_nor/article/details/52979425 对于一个点x,如果我们对x进行access操作,那么他的虚子树内将包含且仅包含他原树中子树内除了他自己以外的所有点,这时如果我们维护了他的虚子树信息和,我们把这个信息与他自己的信息合并,我们就得到了他在原树中的子树信息 在下面的讨论中,我们发现我们可以同时维护一个点的虚子树信息和LCT子树信息来达到维护虚子树信息的目的 考虑一个点的虚子树信息会在什么情况下发生改变,一个点的虚子树信息改变,当且仅当进行link或者access操作时。 在进行access操作时,我们会有更换一个点的x右儿子的操作,这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,把x的新的右儿子的LCT子树信息从x的虚子树信息中减去 在进行link操作时,我们会先把点x换根,然后连一条x到y的虚边,这时我们发现不仅y的虚子树信息需要加入x的LCT子树信息,y的所有祖先的LCT子树信息也需要更改,而这样我们就没法维护了,所以在进行link操作的时候我们需要把y也换根(其实access再splay就行了,不用换成根)