POJ3580 SuperMemo splay伸展树,区间操作
题意:实现一种数据结构,支持对一个数列的 6 种操作:
第 x 个数到第 y 个数之间的数每个加 D;
第 x 个数到第 y 个数之间全部数翻转;
第 x 个数到第 y 个数之间的数,向后循环流动 c 次,即后面 c个数变成这段子序列的最前面 c 个,前面的被挤到后面。
在第 x 个数后面插入一个数 P。
删除第 x 个数。
求第 x 个数到第 y 个数之间的最小数字。
题解:
(待补)
代码先放上:
(是真的长啊,我已经是比较压行的选手了,依然写了230行)
1.利用stack回收内存池
- #include <cstdio>
- #include <stack>
- #include <cstring>
- #include <vector>
- #define ll long long
- #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
- using namespace std;
- const int maxn=1e6+10,maxm=2e6+10;
- const int INF=0x3f3f3f3f;
- class splaytree{
- public:
- struct splaynode{
- splaynode *son[2],*pre;
- ll val,tag,mn;
- int size,rev;
- void init(ll x){
- pre=son[1]=son[0]=NULL;
- mn=val=x;
- tag=rev=0;
- size=1;
- }
- void add(ll x){tag+=x,mn+=x;}
- };
- typedef struct splaynode* nodep;
- int cnt;
- stack<nodep> stk;
- nodep root;
- vector<splaynode> node;
- int getsize(nodep x){return x?x->size:0;}
- void pushdown(nodep now){
- if(!now) return ;
- if(now->tag){
- ll tag=now->tag;
- now->val+=tag;
- if(now->son[0]) now->son[0]->add(tag);
- if(now->son[1]) now->son[1]->add(tag);
- now->tag=0;
- }
- if(now->rev){
- swap(now->son[0],now->son[1]);
- now->rev=0;
- if(now->son[0]) now->son[0]->rev^=1;
- if(now->son[1]) now->son[1]->rev^=1;
- }
- }
- void pushup(nodep now){
- if(!now) return ;
- now->size=1,now->mn=now->val;
- if(now->son[0]) {
- now->mn=min(now->mn,now->son[0]->mn);
- now->size+=now->son[0]->size;
- }
- if(now->son[1]){
- now->mn=min(now->mn,now->son[1]->mn);
- now->size+=now->son[1]->size;
- }
- }
- void rotate(nodep now,int d){
- nodep fa=now->pre;
- pushdown(fa);
- pushdown(now);
- pushdown(now->son[d]);
- fa->son[!d]=now->son[d];
- if(now->son[d]) now->son[d]->pre=fa;
- now->pre=fa->pre;
- if(fa->pre){
- if(fa->pre->son[0]==fa) fa->pre->son[0]=now;
- else fa->pre->son[1]=now;
- }else root=now;
- now->son[d]=fa;
- fa->pre=now;
- pushup(fa);
- }
- void splay(nodep now,nodep dst){
- pushdown(now);
- while(now!=dst){
- if(now->pre==dst){
- if(dst->son[0]==now) rotate(now,1);
- else rotate(now,0);
- break;
- }
- nodep fa=now->pre,gfa=fa->pre;
- if(gfa->son[0]==fa){
- if(fa->son[0]==now) {rotate(fa,1);rotate(now,1);}
- else {rotate(now,0);rotate(now,1);}
- }else {
- if(fa->son[1]==now) {rotate(fa,0);rotate(now,0);}
- else {rotate(now,1);rotate(now,0);}
- }
- if(gfa==dst) break;
- pushup(now);
- }
- pushup(now);
- }
- void find(int k,nodep fa){
- int tmp;
- nodep t=root;
- while (1) {
- pushdown(t);
- tmp=getsize(t->son[0]);
- if (k==tmp+1) break;
- if (k<=tmp) t=t->son[0];
- else {
- k-=tmp+1,t=t->son[1];
- }
- }
- pushdown(t);
- splay(t, fa);
- }
- void findseg(int s,int t){
- find(s,root);
- find(t+2,root->son[1]);
- }
- void insert(int pos,ll val){
- findseg(pos+1,pos);
- nodep now,fa=root->son[1];
- pushdown(root);
- pushdown(fa);
- if(!stk.empty()){
- now=stk.top();
- stk.pop();
- }else now=&node[cnt++];
- now->init(val);
- now->son[1]=fa;
- fa->pre=now;
- root->son[1]=now;
- now->pre=root;
- splay(fa,root);
- }
- void add(int s,int t,ll val){
- findseg(s,t);
- nodep now = root->son[1]->son[0];
- pushdown(now);
- pushup(now);
- now->mn+=val;
- now->tag+=val;
- splay(now,root);
- }
- void reverse(int s,int t){
- findseg(s,t);
- root->son[1]->son[0]->rev^=1;
- nodep now=root->son[1]->son[0];
- splay(now,root);
- }
- void revolve(int s,int t,int len){
- nodep x,y;
- findseg(s,t);
- find(t+1-len,root->son[1]->son[0]);
- x=root->son[1]->son[0];
- pushdown(x);
- y=x->son[1];
- x->son[1]=NULL;
- find(s+1,root->son[1]->son[0]);
- x=root->son[1]->son[0];
- pushdown(x);
- x->son[0]=y;
- y->pre=x;
- splay(y,root);
- }
- ll getmin(int s,int t) {
- findseg(s,t);
- nodep now=root->son[1];
- pushdown(now);
- now=now->son[0];
- pushdown(now);
- pushup(now);
- return now->mn;
- }
- void erase(int pos){
- findseg(pos, pos);
- pushdown(root->son[1]);
- stk.push(root->son[1]->son[0]);
- root->son[1]->son[0] = NULL;
- nodep now = root->son[1];
- splay(now,root);
- }
- splaytree(ll*a,int n){
- cnt=0;
- node.resize(maxn);
- root=&node[cnt++];
- root->init(INF);
- root->son[1]=&node[cnt++];
- root->son[1]->init(INF);
- while (!stk.empty()) stk.pop();
- rep(i,0,n-1) insert(i, a[i]);
- }
- };
- ll v[maxn];
- int main() {
- int n, m;
- scanf("%d", &n);
- rep(i,0,n-1) scanf("%lld",&v[i]);
- scanf("%d", &m);
- splaytree tree(v, n);
- while (m--) {
- char s[50];
- scanf("%s",s);
- if (s[0]=='A') {
- int l, r, d;
- scanf("%d%d%d",&l,&r,&d);
- tree.add(l,r,d);
- }
- if (s[0]=='R') {
- int l, r;
- scanf("%d%d",&l,&r);
- if (s[3]=='E') tree.reverse(l,r);
- else {
- int k;
- scanf("%d",&k);
- int tn=r-l+1;
- k=(k%tn+tn)%tn;
- if (l==r||k==0) continue;
- tree.revolve(l,r,k);
- }
- }
- if (s[0]=='I') {
- int x, d;
- scanf("%d%d",&x,&d);
- tree.insert(x,d);
- }
- if (s[0]=='D') {
- int x;
- scanf("%d",&x);
- tree.erase(x);
- }
- if (s[0]=='M') {
- int l, r;
- scanf("%d%d",&l,&r);
- printf("%lld\n",tree.getmin(l,r));
- }
- }
- return 0;
- }
2.不用stack
- #include <iostream>
- #include <vector>
- #define ll long long
- #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
- using namespace std;
- const int maxn=1e6+10,maxm=2e6+10;
- const int INF=0x3f3f3f3f;
- class splaytree{
- public:
- struct splaynode{
- splaynode *son[2],*pre;
- ll val,tag,mn;
- int size,rev;
- void init(ll x){
- pre=son[1]=son[0]=NULL;
- mn=val=x;
- tag=rev=0;
- size=1;
- }
- void add(ll x){tag+=x,mn+=x;}
- };
- typedef struct splaynode* nodep;
- int cnt;
- nodep root;
- vector<splaynode> node;
- int getsize(nodep x){return x?x->size:0;}
- void pushdown(nodep now){
- if(!now) return ;
- if(now->tag){
- ll tag=now->tag;
- now->val+=tag;
- if(now->son[0]) now->son[0]->add(tag);
- if(now->son[1]) now->son[1]->add(tag);
- now->tag=0;
- }
- if(now->rev){
- swap(now->son[0],now->son[1]);
- now->rev=0;
- if(now->son[0]) now->son[0]->rev^=1;
- if(now->son[1]) now->son[1]->rev^=1;
- }
- }
- void pushup(nodep now){
- if(!now) return ;
- now->size=1,now->mn=now->val;
- if(now->son[0]) {
- now->mn=min(now->mn,now->son[0]->mn);
- now->size+=now->son[0]->size;
- }
- if(now->son[1]){
- now->mn=min(now->mn,now->son[1]->mn);
- now->size+=now->son[1]->size;
- }
- }
- void rotate(nodep now,int d){
- nodep fa=now->pre;
- pushdown(fa);
- pushdown(now);
- pushdown(now->son[d]);
- fa->son[!d]=now->son[d];
- if(now->son[d]) now->son[d]->pre=fa;
- now->pre=fa->pre;
- if(fa->pre){
- if(fa->pre->son[0]==fa) fa->pre->son[0]=now;
- else fa->pre->son[1]=now;
- }else root=now;
- now->son[d]=fa;
- fa->pre=now;
- pushup(fa);
- }
- void splay(nodep now,nodep dst){
- pushdown(now);
- while(now!=dst){
- if(now->pre==dst){
- if(dst->son[0]==now) rotate(now,1);
- else rotate(now,0);
- break;
- }
- nodep fa=now->pre,gfa=fa->pre;
- if(gfa->son[0]==fa){
- if(fa->son[0]==now) {rotate(fa,1);rotate(now,1);}
- else {rotate(now,0);rotate(now,1);}
- }else {
- if(fa->son[1]==now) {rotate(fa,0);rotate(now,0);}
- else {rotate(now,1);rotate(now,0);}
- }
- if(gfa==dst) break;
- pushup(now);
- }
- pushup(now);
- }
- void find(int k,nodep fa){
- int tmp;
- nodep t=root;
- while (1) {
- pushdown(t);
- tmp=getsize(t->son[0]);
- if (k==tmp+1) break;
- if (k<=tmp) t=t->son[0];
- else {
- k-=tmp+1,t=t->son[1];
- }
- }
- pushdown(t);
- splay(t, fa);
- }
- void findseg(int s,int t){
- find(s,root);
- find(t+2,root->son[1]);
- }
- void insert(int pos,ll val){
- findseg(pos+1,pos);
- nodep now,fa=root->son[1];
- pushdown(root);
- pushdown(fa);
- now=&node[cnt++];
- now->init(val);
- now->son[1]=fa;
- fa->pre=now;
- root->son[1]=now;
- now->pre=root;
- splay(fa,root);
- }
- void add(int s,int t,ll val){
- findseg(s,t);
- nodep now = root->son[1]->son[0];
- pushdown(now);
- pushup(now);
- now->mn+=val;
- now->tag+=val;
- splay(now,root);
- }
- void reverse(int s,int t){
- findseg(s,t);
- root->son[1]->son[0]->rev^=1;
- nodep now=root->son[1]->son[0];
- splay(now,root);
- }
- void revolve(int s,int t,int len){
- nodep x,y;
- findseg(s,t);
- find(t+1-len,root->son[1]->son[0]);
- x=root->son[1]->son[0];
- pushdown(x);
- y=x->son[1];
- x->son[1]=NULL;
- find(s+1,root->son[1]->son[0]);
- x=root->son[1]->son[0];
- pushdown(x);
- x->son[0]=y;
- y->pre=x;
- splay(y,root);
- }
- ll getmin(int s,int t) {
- findseg(s,t);
- nodep now=root->son[1];
- pushdown(now);
- now=now->son[0];
- pushdown(now);
- pushup(now);
- return now->mn;
- }
- void erase(int pos){
- findseg(pos, pos);
- pushdown(root->son[1]);
- root->son[1]->son[0] = NULL;
- nodep now = root->son[1];
- splay(now,root);
- }
- splaytree(vector<int> num,int n){
- cnt=0;
- node.resize(n+7);
- root=&node[cnt++];
- root->init(INF);
- root->son[1]=&node[cnt++];
- root->son[1]->init(INF);
- int size=num.size();
- rep(i,0,size-1) insert(i, num[i]);
- }
- };
- int main() {
- ios::sync_with_stdio(false),cin.tie(0);
- int n,m;
- cin>>n;
- vector<int> v(n);
- rep(i,0,n-1) cin>>v[i];
- cin>>m;
- splaytree tree(v,n+m);
- while (m--) {
- string s;
- cin>>s;
- if (s[0]=='A') {
- int l,r,d;cin>>l>>r>>d;
- tree.add(l,r,d);
- }
- if (s[0]=='R') {
- int l,r;cin>>l>>r;
- if (s[3]=='E') tree.reverse(l,r);
- else {
- int k;cin>>k;
- int tn=r-l+1;
- k=(k%tn+tn)%tn;
- if (l==r||k==0) continue;
- tree.revolve(l,r,k);
- }
- }
- if (s[0]=='I') {
- int x,d;cin>>x>>d;
- tree.insert(x,d);
- }
- if (s[0]=='D') {
- int x;cin>>x;
- tree.erase(x);
- }
- if (s[0]=='M') {
- int l,r;cin>>l>>r;
- cout<<tree.getmin(l,r)<<endl;
- }
- }
- return 0;
- }
POJ3580 SuperMemo splay伸展树,区间操作的更多相关文章
- 2018牛客网暑期ACM多校训练营(第三场) H - Shuffle Cards - [splay伸展树][区间移动][区间反转]
题目链接:https://www.nowcoder.com/acm/contest/141/C 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K ...
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- 【学时总结】◆学时·VI◆ SPLAY伸展树
◆学时·VI◆ SPLAY伸展树 平衡树之多,学之不尽也…… ◇算法概述 二叉排序树的一种,自动平衡,由 Tarjan 提出并实现.得名于特有的 Splay 操作. Splay操作:将节点u通过单旋. ...
- Splay伸展树入门(单点操作,区间维护)附例题模板
Pps:终于学会了伸展树的区间操作,做一个完整的总结,总结一下自己的伸展树的单点操作和区间维护,顺便给未来的自己总结复习用. splay是一种平衡树,[平均]操作复杂度O(nlogn).首先平衡树先是 ...
- [置顶] hdu 1890 伸展树区间翻转
题意: 给你n个数,每次先输出第i大的数的位置(如果有多个,选下标小的那个),然后每次将第i个位置到第i大的数所在位置之间的数进行翻转. 思路:输入的数组可能有多个相同的值,我们可以进行两次排序把数组 ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
- [算法] 数据结构 splay(伸展树)解析
前言 splay学了已经很久了,只不过一直没有总结,鸽了好久来写一篇总结. 先介绍 splay:亦称伸展树,为二叉搜索树的一种,部分操作能在 \(O( \log n)\) 内完成,如插入.查找.删除. ...
- Splay 伸展树
废话不说,有篇论文可供参考:杨思雨:<伸展树的基本操作与应用> Splay的好处可以快速分裂和合并. ===============================14.07.26更新== ...
- UVA 11922 Permutation Transformer —— splay伸展树
题意:根据m条指令改变排列1 2 3 4 … n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘 ...
随机推荐
- UDP协议
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/7532512 更多请看专栏, ...
- Elasticsearch 集群 单服务器 超级详细教程
前言 之前了解了Elasticsearch的基本概念.将spring boot + ElasticSearch + head插件 搞通之后.紧接着对es进行下一步的探索:集群.查阅资料的过程中,找到了 ...
- log 的 debug()、 error()、 info()方法
log4j定义了8个级别的log(除去OFF和ALL,可以说分为6个级别),优先级从高到低依次为:OFF.FATAL.ERROR.WARN.INFO.DEBUG.TRACE. ALL. 简单的说,就是 ...
- 从零开始搭建高性能高可用Tomcat服务器
目标: Tomcat+Nginx+Memcached Ubuntu 16.04 64位测试通过 动静分类.负载均衡.集群.Javolution序列化.高性能.高可用 配置环境(目前均为最新稳定版): ...
- ArcGis Python脚本——批量添加字段
先看如何增加一个字段 函数:arcpy.AddField_management 语法:AddFields_management (in_table, field_description) 参数 说明 ...
- [Android] Android 异步定时任务实现的三种方法(以SeekBar的进度自动实现为例)
[Android] Android 定时异步任务实现的三种方法(以SeekBar的进度自动实现为例) 一.采用Handler与线程的sleep(long)方法 二.采用Handler与timer及Ti ...
- jsp过滤器
1.ip过滤 IpFilter: package com.cn.filter; import java.io.IOException; import javax.servlet.Filter; imp ...
- 账号管理文件/etc/passwd和/etc/shadow
/etc/passwd和/etc/shadow是Linux中两个账号管理的重要文件 一./etc/passwd 这个文件中每一行代表一个账号,有几行就代表系统中存在几个账号.有些账号是系 ...
- springboot13 发布和监听事件
spring中的事件驱动模型Event(也叫发布订阅模式),是观察者模式的一个典型的应用 好处:业务解耦,在不影响原来业务逻辑的情况下,加入其它业务 场景: app上线后已实现用户注册功能,现需要在用 ...
- Docker(二)搭建和使用Docker
摘自 https://mp.weixin.qq.com/s/E9tqhe00EjfV8y1pqWkZfw 一.Docker的架构 Docker使用C/S结构,即客户端/服务器体系结构.Docker客户 ...