ZOJ 3765 Lights (zju March I)伸展树Splay
ZJU 三月月赛题,当时见这个题目没辙,没学过splay,敲了个链表TLE了,所以回来好好学了下Splay,这道题目是伸展树的第二题,对于伸展树的各项操作有了更多的理解,这题不同于上一题的用指针表示整个树,采用纯数组表示,null节点即为0节点,这样就带来一个问题,就是有时候会有事没事就指向0节点,结果把0节点也算在结果里面,弄得我要几个地方都判断下。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 310000
using namespace std;
int tot,root,n,m;
int ch[N][],val[N],gcdst[N][],size[N],sta[N],pre[N];
int num[N],state[N];
int gcd(int a,int b) //这里处理gcd注意下,因为有-1要独判一下
{
if (a==-)
return b;
if (b==-)
return a;
if (a<b)
{
swap(a,b);
}
return b== ? a : gcd(b,a%b);
}
void newnode(int &rt,int fa,int v,int s)
{
rt=++tot;
ch[rt][]=ch[rt][]=;
val[rt]=v;
pre[rt]=fa;
gcdst[rt][s]=v;
gcdst[rt][s^]=-;
size[rt]=;
sta[rt]=s;
}
void pushup(int rt) //为了求不同状态的gcd,索性把每个gcd都求出来。然后再选择正确的状态的作为该点的gcd
{
int ll=ch[rt][],rr=ch[rt][];
size[rt]=;
if (ll) size[rt]+=size[ll];
if (rr) size[rt]+=size[rr];
if (!ll)
gcdst[ll][]=gcdst[ll][]=-;
if (!rr)
gcdst[rr][]=gcdst[rr][]=-;
gcdst[rt][]=gcd(gcdst[ll][],gcdst[rr][]);
gcdst[rt][]=gcd(gcdst[ll][],gcdst[rr][]);
gcdst[rt][sta[rt]]=gcd(gcdst[rt][sta[rt]],val[rt]);
}
void rotate(int x,int c)
{
int y=pre[x];
ch[y][!c]=ch[x][c];
if (ch[x][c])
{
pre[ch[x][c]]=y;
}
pre[x]=pre[y];
if (pre[y])
{
if (ch[pre[y]][]==y)
ch[pre[y]][]=x;
else
ch[pre[y]][]=x;
}
ch[x][c]=y;
pre[y]=x;
pushup(y);
if (x)
pushup(x);
if (root==y)
root=x;
}
void splay(int x,int f)
{
while (pre[x]!=f)
{
if (pre[pre[x]]==f)
{
if (ch[pre[x]][]==x)
{
rotate(x,);
}
else
rotate(x,);
}
else
{
int y=pre[x],z=pre[y];
if (ch[z][]==y)
{
if (ch[y][]==x)
{
rotate(y,);
rotate(x,);
}
else
{
rotate(x,);
rotate(x,);
}
}
else
{
if (ch[y][]==x)
{
rotate(x,);
rotate(x,);
}
else
{
rotate(y,);
rotate(x,);
}
}
}
}
pushup(x);
if (f)
pushup(f);
}
void select(int k,int f)
{
int x=root;
//cout<<"root is "<<x<<" left child is "<<ch[x][0]<<endl;
int tmp=;
k++;
for (;;)
{
tmp=;
if (ch[x][])
tmp=size[ch[x][]];
// cout<<k<<" "<<tmp<<endl;
//int temp;
//cin>>temp;
if (tmp+==k) break;
if (k<=tmp)
x=ch[x][];
else{
k-=tmp+;
x=ch[x][];
}
}
//cout<<"test "<<pre[x]<<" "<<f<<endl;
splay(x,f);
}
void add(int num,int v,int s)//插入操作,把要插入的位置先移到根,再处理即可
{
select(num,);
int nt;
int x=ch[root][];
int p=root;
while (x)
{
// cout<<x<<" tianjia "<<val[x]<<endl;
p=x;
x=ch[x][];
}
//`cout<<x<<" final "<<val[x]<<" "<<p<<" "<<val[p]<<endl; if (p==root)
{
newnode(ch[p][],p,v,s);
splay(ch[p][],);
}
else
{ newnode(ch[p][],p,v,s);
splay(ch[p][],);
}
}
void deletes(int num) //删除某个点,这个需要考虑下,若左子树或者右子树为空,则可直接消除,否则找到左子树的最大节点移到根,然后被删除的点即在右节点上,删除即可
{
select(num,);
if (ch[root][]==)
{
root=ch[root][];
pre[root]=;
return;
}
if (ch[root][]==)
{
root=ch[root][];
pre[root]=;
return;
}
int rc=ch[root][];
while (ch[rc][])
rc=ch[rc][];
splay(rc,root);
ch[rc][]=ch[root][];
pre[ch[root][]]=rc;
root=rc;
pre[root]=;
pushup(root);
}
void change(int k)
{
select(k,);
sta[root]^=;
pushup(root);
}
void query(int l,int r,int s)//查询某个区间的gcd,只要把区间的前一个节点放在根节点 后一个节点放在根的右节点,则区间必定就在根的右节点的左节点上
{
select(l-,);
// cout<<"pass"<<endl;
select(r+,root);
//cout<<"pass"<<endl;
int rt=ch[ch[root][]][];
//pushup(rt);
//cout<<rt<<" "<<gcdst[rt][s]<<" "<<gcdst[rt][1-s]<<endl;
printf("%d\n",gcdst[rt][s]);
}
void modify(int k,int v)//修改某个值,这无疑是最简单的操作,移到根节点后直接修改即可
{
select(k,);
val[root]=v;
pushup(root);
}
void build(int l,int r,int &rt,int fa)//建树过程
{
if (l>r) return;
int mid=(l+r)>>;
newnode(rt,fa,num[mid],state[mid]);
build(l,mid-,ch[rt][],rt);
build(mid+,r,ch[rt][],rt);
pushup(rt);
}
void init() //初始化过程
{
for (int i=;i<=n;i++)
{
scanf("%d%d",&num[i],&state[i]);
}
root=tot=;
ch[][]=ch[][]=;
pre[]=size[]=;val[]=-;
gcdst[][]=gcdst[][]=-;
newnode(root,,,-);
newnode(ch[root][],root,,-);
build(,n,ch[ch[root][]][],ch[root][]);
pushup(ch[root][]);
pushup(root);
}
void test() //测试最终生成的树
{
int d=size[root];
for (int i=;i<d-;i++)
{
select(i,);
cout<<i<<" val is "<<val[root]<<" state "<<sta[root]<<" gcd[0] "<<gcdst[root][]<<" gcd[1] "<<gcdst[root][]<<endl;
}
}
int main()
{
char ques[];
int a,b,c;
while (scanf("%d%d",&n,&m)!=EOF)
{
init();
//cout<<" "<<size[root]<<endl;
for (int i=;i<m;i++)
{
getchar();
scanf("%s",ques);
//puts(ques);
if (ques[]=='Q')
{
scanf("%d%d%d",&a,&b,&c);
//cout<<"pass"<<endl;
query(a,b,c);
// cout<<"p2"<<endl;
}
if (ques[]=='I')
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
if (ques[]=='D')
{
scanf("%d",&a);
deletes(a);
}
if (ques[]=='R')
{
scanf("%d",&a);
change(a);
}
if (ques[]=='M')
{
scanf("%d%d",&a,&b);
modify(a,b);
}
// test(); }
}
return ;
}
ZOJ 3765 Lights (zju March I)伸展树Splay的更多相关文章
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- 纸上谈兵: 伸展树 (splay tree)[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...
- K:伸展树(splay tree)
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...
- 高级搜索树-伸展树(Splay Tree)
目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...
- ZOJ 3765 Lights (伸展树splay)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3765 Lights Time Limit: 8 Seconds ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
- 伸展树Splay【非指针版】
·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...
- 伸展树(Splay tree)的基本操作与应用
伸展树的基本操作与应用 [伸展树的基本操作] 伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性.即伸展树中的每一个节点 x 都满足:该节点左子树中的每一个元素都小于 x,而其右子树中 ...
随机推荐
- 7.8 Varnish 其他命令
- MQTT 协议学习:004-MQTT建立通信与 CONNECT 、CONNACK 报文
背景 上一讲 MQTT 协议学习:通信报文的构成介绍了在MQTT通信中,各报文的通信流程:从本讲开始,我们开始介绍实际中使用的报文,以及它们的组成. CONNECT - 连接请求 报文 客户端到服务端 ...
- Web基础之Spring AOP与事务
Spring之AOP AOP 全程Aspect Oriented Programming,直译就是面向切面编程.和POP.OOP相似,它也是一种编程思想.OOP强调的是封装.继承.多态,也就是功能的模 ...
- Oracle 子程序、过程、函数
一.子程序 子程序是一个数据库对象,存在于数据库中,里面存放的是PL/SQL代码,可以完成一定的共能,能被程序和客户端工具直接调用.子程序类似于java中的方法,可以接接收参数,按照是否有返回值,子程 ...
- php.laravel.middleware
关于中间件,在php-laravel中的定义就是对请求的一个过滤,相当于JSP技术中的filter的存在.需要知道编写了一个中间件可以配置在三个地方(就目前5.7版本而言)让其发挥作用,具体需要看/a ...
- 【Cantor表】蒟蒻题解
原题:传送门 (上图摘自网站OpenJudge - NOI题库2.1 Cantor表) 本蒟蒻的题解,让大神们见笑了! 首先,进行找规律. 大家可以发现: 1.当分子是一的时候,且分子和分母的和是偶数 ...
- 记录第一次制作pypi包的过程
准备工作 1.创建一个项目文件夹 mkdir dada_openapi_python cd dada_openapi_python 2.创建包文件夹 在里面在创建一个 dada_openapi_cli ...
- 九十一、SAP中ALV事件之五,查看状态栏,工具栏和功能键等
一.我们按照说明,来到SE37功能模块,然后点击[转到]->[函数组]->[显示组] 二.按照说明输入SALV,点击勾选 三.点击主程序 四.点击主程序后,我们来到函数组页面,然后 五.我 ...
- 简述哲学Essay写作
哲学类essay写作对于中国留学生来说算是比较难的作业了,它不仅有结构要求,还注重逻辑的紧密性.很多同学都不知道该怎么下手.今天小编就给同学们分享哲学essay写作的结构.同学们可以尝试按照以下方法来 ...
- Unity UGUI优化整理
看了不少UI优化方面的东西,还是记下来方便记忆,优化性能往往是在各种选择之间做出平衡(空间换时间,或者GPU换CPU,舍弃精度等). 主要优化点在减少Drawcall,减少Overdraw. Mask ...