POJ3580:SuperMemo
浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html
浅谈\(fhq\)_\(treap\):https://www.cnblogs.com/AKMer/p/9981274.html
题目传送门:http://poj.org/problem?id=3580
对于\(REVOLVE\)操作,就相当于把\([r-t+1,r]\)剪切下来粘贴到\([l-1,l]\)中间,其余的操作都是平衡树较为模板的操作了。记得把零号点的最小值赋成\(inf\),要不然空儿子更新父亲信息就会出错。下传标记记得不要传给空儿子,否则会加爆。
时间复杂度:\(O((n+m)logn)\)
空间复杂度:\(O(n)\)
\(splay\)代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=2e5+5,inf=2e9;
int n,m;
char s[10];
int a[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Splay {
int tot,root;
bool rev[maxn];
int add[maxn],val[maxn],mn[maxn];
int siz[maxn],fa[maxn],son[maxn][2];
int newnode(int v) {
siz[++tot]=1;
val[tot]=mn[tot]=v;
return tot;
}
void update(int p) {
siz[p]=siz[son[p][0]]+1+siz[son[p][1]];
mn[p]=min(min(mn[son[p][0]],mn[son[p][1]]),val[p]);
}
void build(int l,int r,int lst) {
if(r<l)return;
if(l==r) {
siz[l]=1,val[l]=mn[l]=a[l];
fa[l]=lst,son[lst][l>lst]=l;
return;
}
int mid=(l+r)>>1;
val[mid]=a[mid];
fa[mid]=lst,son[lst][mid>lst]=mid;
build(l,mid-1,mid),build(mid+1,r,mid);
update(mid);
}
void prepare() {
mn[0]=inf,tot=n+2,build(1,n+2,0),root=(n+3)>>1;
}
void make_rev_tag(int p) {
if(!p)return;
rev[p]^=1,swap(son[p][0],son[p][1]);
}
void make_add_tag(int p,int v) {
if(!p)return;
val[p]+=v,add[p]+=v,mn[p]+=v;
}
void push_down(int p) {
if(rev[p]) {
make_rev_tag(son[p][0]);
make_rev_tag(son[p][1]);
rev[p]=0;
}
if(add[p]) {
make_add_tag(son[p][0],add[p]);
make_add_tag(son[p][1],add[p]);
add[p]=0;
}
}
int find(int u,int rk) {
push_down(u);
if(siz[son[u][0]]+1==rk)return u;
if(siz[son[u][0]]>=rk)return find(son[u][0],rk);
return find(son[u][1],rk-siz[son[u][0]]-1);
}
int t(int u) {
return son[fa[u]][1]==u;
}
void rotate(int u) {
int ret=t(u),f=fa[u],s=son[u][ret^1];
son[f][ret]=s;if(s)fa[s]=f;son[u][ret^1]=f;
fa[u]=fa[f];if(fa[f])son[fa[f]][t(f)]=u;
fa[f]=u;update(f),update(u);
}
void splay(int goal,int u) {
int tmp=fa[goal];
while(fa[u]!=tmp) {
if(fa[fa[u]]!=tmp) {
if(t(fa[u])==t(u))rotate(fa[u]);
else rotate(u);
}
rotate(u);
}
if(!tmp)root=u;
}
void ADD(int l,int r,int v) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
make_add_tag(son[u2][0],v);
update(u2),update(u1);
}
void REVERSE(int l,int r) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
make_rev_tag(son[u2][0]);
}
int cut(int l,int r) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
int tmp=son[u2][0];
son[u2][0]=fa[tmp]=0;
update(u2),update(u1);
return tmp;
}
void paste(int pos,int node) {
int u1=find(root,pos-1),u2=find(root,pos);
splay(root,u1),splay(son[u1][1],u2);
fa[node]=u2,son[u2][0]=node;
update(u2),update(u1);
}
int query(int l,int r) {
int u1=find(root,l-1),u2=find(root,r+1);
splay(root,u1),splay(son[u1][1],u2);
return mn[son[u2][0]];
}
}T;
int main() {
n=read();
for(int i=2;i<=n+1;i++)
a[i]=read();
a[1]=a[n+2]=inf;
T.prepare();m=read();
for(int i=1;i<=m;i++) {
scanf("%s",s+1);
if(s[1]=='A') {
int l=read()+1,r=read()+1,v=read();
T.ADD(l,r,v);
}
if(s[1]=='R') {
int l=read()+1,r=read()+1;
if(s[4]=='E')T.REVERSE(l,r);
else {
int t=read()%(r-l+1);
int tmp=T.cut(r-t+1,r);
T.paste(l,tmp);
}
}
if(s[1]=='I') {
int pos=read()+1,v=read();
T.paste(pos+1,T.newnode(v));
}
if(s[1]=='D') {
int pos=read()+1;
T.cut(pos,pos);
}
if(s[1]=='M') {
int l=read()+1,r=read()+1;
printf("%d\n",T.query(l,r));
}
}
return 0;
}
\(fhq\)_\(treap\)版代码如下:
#include <ctime>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef pair<int,int> pii;
const int maxn=2e5+5,inf=2e9;
int n,m;
char s[10];
int a[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct fhq_treap {
int tot,root;
bool rev[maxn];
int val[maxn],mn[maxn],add[maxn];
int siz[maxn],fix[maxn],son[maxn][2];
int newnode(int v) {
siz[++tot]=1;
fix[tot]=rand();
val[tot]=mn[tot]=v;
return tot;
}
void update(int p) {
siz[p]=siz[son[p][0]]+1+siz[son[p][1]];
mn[p]=min(min(mn[son[p][0]],mn[son[p][1]]),val[p]);
}
void build(int l,int r,int lst) {
if(r<l)return;
if(l==r) {
siz[l]=1,fix[l]=rand();
son[lst][l>lst]=l;
val[l]=mn[l]=a[l];
return;
}
int mid=(l+r)>>1;
val[mid]=a[mid],fix[mid]=rand();
son[lst][mid>lst]=mid;
build(l,mid-1,mid),build(mid+1,r,mid);
update(mid);
}
void prepare() {
mn[0]=inf,tot=n,build(1,n,0),root=(n+1)>>1;
}
void make_add_tag(int u,int v) {
if(!u)return;
val[u]+=v,add[u]+=v,mn[u]+=v;
}
void make_rev_tag(int u) {
if(!u)return;
rev[u]^=1,swap(son[u][0],son[u][1]);
}
void push_down(int u) {
if(add[u]) {
make_add_tag(son[u][0],add[u]);
make_add_tag(son[u][1],add[u]);
add[u]=0;
}
if(rev[u]) {
make_rev_tag(son[u][0]);
make_rev_tag(son[u][1]);
rev[u]=0;
}
}
pii split(int u,int rk) {
if(!rk)return make_pair(0,u);
if(rk==siz[u])return make_pair(u,0);
push_down(u);
if(siz[son[u][0]]>=rk) {
pii tmp=split(son[u][0],rk);
son[u][0]=tmp.second,update(u);
return make_pair(tmp.first,u);
}
else {
pii tmp=split(son[u][1],rk-siz[son[u][0]]-1);
son[u][1]=tmp.first,update(u);
return make_pair(u,tmp.second);
}
}
int merge(int a,int b) {
if(!a||!b)return a+b;
push_down(a),push_down(b);
if(fix[a]>fix[b])return son[a][1]=merge(son[a][1],b),update(a),a;
else return son[b][0]=merge(a,son[b][0]),update(b),b;
}
void ADD(int l,int r,int v) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
make_add_tag(tmp2.second,v);
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
}
void REVERSE(int l,int r) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
make_rev_tag(tmp2.second);
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
}
int cut(int l,int r) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
root=merge(tmp2.first,tmp1.second);
return tmp2.second;
}
void paste(int pos,int node) {
pii tmp=split(root,pos-1);
root=merge(merge(tmp.first,node),tmp.second);
}
int query(int l,int r) {
pii tmp1=split(root,r);
pii tmp2=split(tmp1.first,l-1);
int res=mn[tmp2.second];
root=merge(merge(tmp2.first,tmp2.second),tmp1.second);
return res;
}
}T;
int main() {
srand(time(0)),n=read();
for(int i=1;i<=n;i++)
a[i]=read();
T.prepare();m=read();
for(int i=1;i<=m;i++) {
scanf("%s",s+1);
if(s[1]=='A') {
int l=read(),r=read(),v=read();
T.ADD(l,r,v);
}
if(s[1]=='R') {
int l=read(),r=read();
if(s[4]=='E')T.REVERSE(l,r);
else {
int t=read()%(r-l+1);
int tmp=T.cut(r-t+1,r);
T.paste(l,tmp);
}
}
if(s[1]=='I') {
int pos=read(),v=read();
T.paste(pos+1,T.newnode(v));
}
if(s[1]=='D') {
int pos=read();
T.cut(pos,pos);
}
if(s[1]=='M') {
int l=read(),r=read();
printf("%d\n",T.query(l,r));
}
}
return 0;
}
POJ3580:SuperMemo的更多相关文章
- POJ 3580:SuperMemo(Splay)
http://poj.org/problem?id=3580 题意:有6种操作,其中有两种之前没做过,就是Revolve操作和Min操作.Revolve一开始想着一个一个删一个一个插,觉得太暴力了,后 ...
- 【无旋式treap】例题
[bzoj3223]文艺平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[ ...
- 【无旋 treap】例题
[bzoj3223]文艺平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[ ...
- java web 开发三剑客 -------电子书
Internet,人们通常称为因特网,是当今世界上覆盖面最大和应用最广泛的网络.根据英语构词法,Internet是Inter + net,Inter-作为前缀在英语中表示“在一起,交互”,由此可知In ...
- 所有selenium相关的库
通过爬虫 获取 官方文档库 如果想获取 相应的库 修改对应配置即可 代码如下 from urllib.parse import urljoin import requests from lxml im ...
- 平衡树(Splay):Splaytree POJ 3580 SuperMemo
SuperMemo Description Your friend, Jackson is invited to a TV show called SuperMemo in which ...
- poj3580 SuperMemo (Splay+区间内向一个方向移动)
Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 13550 Accepted: 4248 Case Time Limit: ...
- 【POJ3580】【splay版】SuperMemo
Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant i ...
- 【POJ3580】【块状链表】SuperMemo
Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant i ...
随机推荐
- (webstorm的css编写插件)Emmet:HTML/CSS代码快速编写神器
Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: ...
- 卡特兰数-Catalan数
卡特兰数的含义: 说到卡特兰数,就不得不提及卡特兰数序列.卡特兰数序列是一个整数序列.其通项公式是我们从中取出的就叫做第n个卡特兰数数,前几个卡特兰数数是:1, 1, 2, 5, 14, 42, 13 ...
- PHPExcel简易使用教程
在企业里使用PHP进行开发,不可避免总会遇到读/写Excel的需求,遇到这种需求,一般使用PHPExcel类库进行开发. PHPExcel现在最新版本是1.8.0,最低需要PHP5.2版本,支持读取x ...
- string去空格
众所周知,string字符串去除空格的方法有trim()和replace(),区别在于trim()去首尾的空格,但是不能去中间的,而replace可以去除所有的空格. string data1=&qu ...
- python从安装与使用pip到入门
官方下载地址:https://www.python.org/downloads/ 下载后直接安装就可以了 再配一下环境变量, cmd运行python -V (注意,这里是大写的V) 打开python跑 ...
- python 基础 7.5 commands 模块
一. commands 模块 1.commands 模块只使用与linxu 的shell 模式下 在我们平时码字时,经常需要调用系统脚本或者系统命令来解决很多问题,接下来,我们就介绍给大家一个很好 ...
- python 基础及资料汇总
Python 包.模块.类以及代码文件和目录的一种管理方案 Numpy 小结 用 Python 3 的 async / await 做异步编程 K-means 在 Python 中的实现 ...
- ajax实时获取下拉数据
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> ajax ...
- sql性能分析语句
SELECT creation_time N'语句编译时间' ,last_execution_time N'上次执行时间' ,total_physical_reads N'物理读取总次数' ,tota ...
- Java for LeetCode 138 Copy List with Random Pointer
A linked list is given such that each node contains an additional random pointer which could point t ...