splay

题解【部落冲突】

懵懂的女人 提交于 2020-02-04 11:19:39
LCT学习ing……从FlshHu的大佬的博客中看到此题,于是便写了一下。 题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落。其中最为强大的是罗马、高卢和日耳曼。他们之间为了争夺资源和土地,进行了无数次的战斗。期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事。 其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这些部落与部落之间相连的道路看作一颗树,可见每条道路对于Travian世界的重要程度。有了这些道路,建筑工人就可以通过这些道路进行友好外交啦。 然而,事情并不会像想象的那样美好,由于资源的匮乏,相邻的部落(由一条道路相连的部落)之间经常会发生大大小小的冲突事件,更有甚者,会升级为部落之间的大型战争。 为了避免误伤,每当两个相邻的部落之间发生大型战争之时,这两个部落间的道路是不允许通行的,对于一些强大的部落,甚至能与多个相邻的部落同时开战,同样的,这些战争地带的道路十分危险,是不可通行的。 天下之势,分久必合,当两个部落经历了不打不相识的苦战之后,他们可以签订停战协议(暂时停战,以后依旧可能再次开战),这样,两个部落之间的道路又会重新恢复为可通行状态,建筑工人们又可以经过此地购买最新的大本营设计图纸来强大自己的部落了。 为了简单起见,我们把各大战争事件按发起的时间顺序依次编号

CF573E (平衡树)

倾然丶 夕夏残阳落幕 提交于 2020-02-03 15:06:16
CF573E 题意概要 给出一个长度为 \(n\) 的数列,从中选出一个子序列 \(b[1...m]\) ( 可以为空 ) 使得 \[ \sum_{i=1}^m{b_i*i}\] 最大,输出这个最大值。 其中 \(n\le10^5\) 题解 设 \(dp_{i,j}\) 表示前 \(i\) 个数选择 \(j\) 个数的最大值 那么,转移方程则为: \[ dp_{i,j}=max(dp_{i-1,j},dp_{i-1,j-1}+j*a_i) \] 于是我们就得到了一个 \(n^2\) 的做法 我们考虑优化这个式子。 经 \(dalao\) 证明,发现总有存在一个分界线,这之前的取前者,这之后的取后者 大佬的证明在 这里 我们二分分界线,然后用平衡树维护就好了 顺带一提,我今日方知 \(splay\) 没事多$ splay $几下还会变快 代码 #include<bits/stdc++.h> #include<windows.h> #define lch c[x][0] #define rch c[x][1] using namespace std; typedef long long ll; const int sz=1e5+7; int n; ll v,ans; int rt,cnt; int f[sz]; int c[sz][2]; int siz[sz]; ll val[sz]

[ZJOI2006]书架(权值splay)

不问归期 提交于 2020-02-01 15:38:38
[ZJOI2006]书架(luogu) Description 题目描述 小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。 输入格式 第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式: 1. Top S——表示把编号为S的书放在最上面。 2. Bottom S——表示把编号为S的书放在最下面。 3.

[NOI2005]维护数列(区间splay)

故事扮演 提交于 2020-02-01 10:55:13
[NOI2005]维护数列(luogu) 打这玩意儿真是要了我的老命 Description 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) Code #include <cstdio> #include <cstdlib> #include <algorithm> #define TAGNONE 10000001 using namespace std; const int N=1e6+10; struct node { int size,rev,ch[2],res,prer,prel,tag,fa,sum,val; void clear() { size=rev=ch[0]=ch[1]=res=prer=prel=fa=sum=val=0; tag=TAGNONE; } }f[N]; int x,id[N],tot,n,ru[N],rt,pos,len,d[N],m,cnt; char s[20]; int get() { if(tot==0) return ++cnt; int x=ru[tot--]; return x; } void c_val(int x,int y) { if(!x) return ; f[x].tag=f[x].val=y; f[x].sum=y*f[x].size; f[x]

【模板】普通平衡树(splay)

让人想犯罪 __ 提交于 2020-01-31 10:42:24
安利splay讲解: [洛谷日报第62期]Splay简易教程 【模板】普通平衡树 (luogu) Description 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入 x x 数 删除 x x 数(若有多个相同的数,因只删除一个) 查询 x x 数的排名(排名定义为比当前数小的数的个数 +1 + 1 ) 查询排名为 x x 的数 求 x x 的前驱(前驱定义为小于 x x,且最大的数) 求 x x 的后继(后继定义为大于 x x,且最小的数) 输入格式 第一行为 n n,表示操作的个数,下面 n n 行每行有两个数 \text{opt} opt 和 x x, \text{opt} opt 表示操作的序号( 1 \leq \text{opt} \leq 6 1 ≤ opt ≤ 6 ) 输出格式 对于操作 3,4,5,6 3 , 4 , 5 , 6 每行输出一个数,表示对应答案 Code #include <iostream> using namespace std; const int N=1e5+10; //1:插入xx数 //2:删除xx数(若有多个相同的数,因只删除一个) //3:查询xx数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名) //4:查询排名为xx的数 //5:求xx的前驱

P2286 [HNOI2004]宠物收养场

狂风中的少年 提交于 2020-01-30 08:18:43
P2286 [HNOI2004]宠物收养场 题目描述 凡凡开了一间宠物收养场。收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养场的宠物一个特点值。这样他就能够很方便的处理整个领养宠物的过程了,宠物收养场总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

 ̄綄美尐妖づ 提交于 2020-01-30 05:30:02
平衡树初阶—— AVL 平衡二叉查找树 一、什么是二叉树 1. 什么是树。 计算机科学里面的树本质是一个树状图。树首先是一个有向无环图,由根节点指向子结点。但是不严格的说,我们也研究无向树。所谓无向树就是将有向树的所有边看成无向边形成的树状图。树是一种递归的数据结构,所以我们研究树也是按照递归的方式去研究的。 2. 什么是二叉树。 我们给出二叉树的递归定义如下: (1)空树是一个二叉树。 (2)单个节点是一个二叉树。 (3)如果一棵树中,以它的左右子节点为根形成的子树都是二叉树,那么这棵树本身也是二叉树。 二、BST 1. 什么是二叉排序树。 二叉排序树是一种二叉树,它满足树的中序遍历是有序的。 2.BST ( Binary Search Tree )。 二叉查找树是一种最普通的二叉排序树,一般称作BST,也称为B-树。在这棵树中,满足在任意一个子树中,都满足左子树 < 根节点 < 右子树,即该树的中序遍历满足从小到大排序的结果。 3. 如何构造一个二叉排序树? 很显然,要想构造一个BST,就必须在插入节点时,满足下面的原则: (1)如果节点为空,则直接插入到该节点。 (2)如果节点不为空,且要插入的值小于等于当前节点的值,那么则将该节点插入到左子树当中。 (3)如果节点不为空,且要插入的值大于当前节点的值,那么则将该节点插入到右子树当中。 4. 利用 BST

[ZJOI2006]书架

我的梦境 提交于 2020-01-29 02:03:05
#include<bits/stdc++.h> #define MAXN 400005 using namespace std; int n,q,a,b; string tp; int date[MAXN],bianhao[MAXN]; struct Splay{ int num[MAXN],ch[MAXN][2],sz[MAXN],f[MAXN],cnt[MAXN],rt,tot,tag[MAXN]; int get(int x){ return (x==ch[f[x]][1]); } int up(int x){ sz[x] = cnt[x]; if(ch[x][0])sz[x] = sz[x]+sz[ch[x][0]]; if(ch[x][1])sz[x] = sz[x]+sz[ch[x][1]]; return 0; } int rote(int x){ int y = f[x],z = f[y],k = get(x),p = get(y); if(y==0)return 0; if(z)ch[z][p] = x; if(ch[x][k^1])f[ch[x][k^1]] = y; ch[y][k] = ch[x][k^1]; ch[x][k^1] = y; f[x] = z; f[y] = x; up(y);up(x); return 0; } int splay(int

平衡树(splay)

删除回忆录丶 提交于 2020-01-28 01:38:43
文章目录 1.About splay 2.基本操作 2.1 数组是干啥的? 2.2 基本操作 3.splay 3.1 rotate函数 3.2 splay函数 4.更新操作 4.1 插入函数 4.2 删除函数 5.查询操作 5.1 查询一个数的排名(rank函数) 5.2 查询第k大(kth函数) 5.3 查找一个数的前驱(lower) 5.4 查找一个数的后继(upper) 6. 模板题代码 7. 写在最后 1.About splay s p l a y splay s p l a y 是实现平衡树的一种方法 他需要满足一个条件,就是对于一个点为根节点的子树,他的左子树全部小于根节点,右子树全部大于根节点 那他为什么叫这个名字呢? 我们查询一下百度翻译 但是事实上,感觉 s p l a y splay s p l a y 跟张开没什么关系… 可以说成展开树吧 s p l a y splay s p l a y 的基本功能跟STL里面的 m u l t i s e t multiset m u l t i s e t ( s e t set s e t )比较像 他的思想的 优秀 之处在于,他每次都把操作完\要操作的点旋转到根节点并且保证满足他的性质,这样可以便于操作 2.基本操作 2.1 数组是干啥的? 在 s p l a y splay s p l a y 中我们要用到一些数组

文艺平衡树

自古美人都是妖i 提交于 2020-01-26 18:02:02
#include<bits/stdc++.h> #define MAXN 300005 using namespace std; int n,m,a,b; struct Splay{ int num[MAXN],ch[MAXN][2],sz[MAXN],f[MAXN],cnt[MAXN],rt,tot,tag[MAXN]; int get(int x){ return (x==ch[f[x]][1]); } int up(int x){ sz[x] = cnt[x]; if(ch[x][0])sz[x] = sz[x]+sz[ch[x][0]]; if(ch[x][1])sz[x] = sz[x]+sz[ch[x][1]]; return 0; } int down(int x){ if(tag[x]){ tag[x] = 0; swap(ch[x][0],ch[x][1]); if(ch[x][0])tag[ch[x][0]] = tag[ch[x][0]]^1; if(ch[x][1])tag[ch[x][1]] = tag[ch[x][1]]^1; } } int found(int x){ int now=rt,ans=1; while(1){ if(num[now]<=x){ ans = ans+sz[ch[now][0]]; if(num[now]==x){