Pku3580 supermemo
给出一个初始序列fA1;A2;:::Ang,要求你编写程序支持如下操作:
1. ADD x y D:给子序列fAx:::Ayg的每个元素都加上D。例如对f1,2, 3,4,5g执行"ADD 241" 会得到f1,3,4,5,5g。
2. REVERSE x y:将子序列fAx:::Ayg翻转。例如对f1,2,3,4,5g执行"REVERSE 24"会得到f1,4,3,2,5g。
3. REVOLVE x y T:将子序列fAx:::Ayg旋转T个单位。例如,对f1,2,3,4,5g执行"REVOLVE 2 4 2"会得到f1,3,4,2,5g。
//将1 2 3 4 5 6中的[2,3,4]右移到两个单位
//移动一个单位得到[4,2,3]
//再移动一个单位得到[3,4,2]
4. INSERT x P:在Ax后插入P。例如,对f1,2,3,4,5g执行"INSERT 24"会得到f1,2,4,3,4,5g。
5. DELETE x:删去Ax。例如,对f1,2,3,4,5g执行"DELETE 2"会得到f1,3,4,5g。
6. MIN x y:查询子序列fAx:::Ayg中的最小元素。例如,对于序列f1, 2,3,4,5g,询问"MIN 24"的返回应为2。
输入
第一行包含一个整数n,表示初始序列的长度。
以下n行每行包含一个整数,描述初始的序列。
接下来一行包含一个整数m,表示操作的数目。以下m行每行描述一个操作。n,m<=10^6
输出
对于所有"MIN"操作,输出正确的答案,每行一个。
样例输入
5
1
2
3
4
5
2
ADD 2 4 1
MIN 4 5
样例输出
5
#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,a[600005],c[600005][2],size[600005],fa[600005];
int tag[600005],mn[600005],num[600005],rt;
bool rev[600005];
inline void update(int x)
{
int l=c[x][0],r=c[x][1];
size[x]=size[l]+size[r]+1;
mn[x]=num[x];
if (l) mn[x]=min(mn[x],mn[l]);
if (r) mn[x]=min(mn[x],mn[r]);
}
int build(int l,int r,int x)
{
if (l>r) return 0;
if (l==r){fa[l]=x;size[l]=1;num[l]=mn[l]=a[l];return l;}
int mid=(l+r)>>1;
c[mid][0]=build(l,mid-1,mid);
c[mid][1]=build(mid+1,r,mid);
num[mid]=a[mid];
update(mid);
fa[mid]=x;
return mid;
}
inline void rotate(int x,int &k)
{
int l,r,y=fa[x],z=fa[y];
if (c[y][0]==x)l=0;else l=1;r=l^1;
if (y!=k)
{
if (c[z][0]==y) c[z][0]=x;else c[z][1]=x;
}
else
//如果y就是x所要旋转的目标点
//则此时y又是x的父亲点,所以经过此次旋转,x就到了要到的位置了
k=x;
fa[x]=z; //x的父亲点为z
fa[y]=x; //y的父亲点为x
c[y][l]=c[x][r];
//y的l子结点为从前x的r子结点
fa[c[x][r]]=y;
//从前x的r子结点的父亲点现在变为y
c[x][r]=y;
//x现在的r子结点变为y
update(y);
update(x);
}
void splay(int x,int &k)
//将x旋转到k这个位置
{
int y,z;
while (x!=k)
{
y=fa[x];z=fa[y];
if (y!=k)
{
if (c[y][0]==x^c[z][0]==y)
rotate(x,k);
else
rotate(y,k);
}
rotate(x,k);
}
}
inline void pushdown(int x)
{
int l=c[x][0],r=c[x][1];
if (tag[x])
{
if (l) num[l]+=tag[x],mn[l]+=tag[x],tag[l]+=tag[x];
if (r) num[r]+=tag[x],mn[r]+=tag[x],tag[r]+=tag[x];
tag[x]=0;
}
if (rev[x])
{
rev[x]^=1;rev[l]^=1;rev[r]^=1;
swap(c[x][0],c[x][1]);
}
}
int find(int x,int k)
{
pushdown(x);
if (size[c[x][0]]+1==k) return x;
if (size[c[x][0]]+1<k) return find(c[x][1],k-size[c[x][0]]-1);
else return find(c[x][0],k);
}
inline void add(int l,int r,int p)
{
int x=find(rt,l);
int y=find(rt,r+2);
splay(x,rt);
splay(y,c[x][1]);
tag[c[y][0]]+=p;
num[c[y][0]]+=p;mn[c[y][0]]+=p;
update(y);update(x);
}
inline void rever(int l,int r)
{
int x=find(rt,l),y=find(rt,r+2);
splay(x,rt);splay(y,c[x][1]);
rev[c[y][0]]^=1;
}
/*
inline void revolve(int l,int r,int t)
{
int x=find(rt,l),y=find(rt,r+2),z=find(rt,r-t+2),o=find(rt,r+1);
splay(x,rt);splay(y,c[x][1]);splay(z,c[y][0]);if (c[z][1])splay(o,c[z][1]);
c[o][1]=c[z][0];fa[c[z][0]]=o;c[z][0]=0;
update(o);update(z);update(y);update(x);
}
*/
inline void insert(int l,int p)
{
int x=find(rt,l+1),y=find(rt,l+2);
splay(x,rt);splay(y,c[x][1]);
c[y][0]=++n;num[n]=mn[n]=p;size[n]=1;fa[n]=y;
update(y);update(x);
}
void del(int l)
{
int x=find(rt,l),y=find(rt,l+2);
splay(x,rt);splay(y,c[x][1]);
c[y][0]=0;update(y);update(x);
}
inline int query(int l,int r)
{
int x=find(rt,l),y=find(rt,r+2);
splay(x,rt);splay(y,c[x][1]);
return mn[c[y][0]];
}
int main()
{
n=read();
for (int i=2;i<=n+1;i++)
a[i]=read();
rt=build(1,n+2,0);n+=2;
int Q=read();
while (Q--)
{
char ch[15];scanf("%s",ch);
if (ch[0]=='A')
{
int l=read(),r=read(),p=read();
add(l,r,p);
}
else if (ch[0]=='I')
{
int l=read(),p=read();
insert(l,p);
}
else if (ch[0]=='D')
{
int l=read();
del(l);
}
else if (ch[0]=='M')
{
int l=read(),r=read();
printf("%d\n",query(l,r));
}
else if (ch[0]=='R'&&ch[4]=='R')
{
int l=read(),r=read();
rever(l,r);
}
else
{
int l=read(),r=read(),t=read();
// t=(t%(r-l+1)+(r-l+1))%(r-l+1);
// cout<<"t is "<<t<<endl;
t=t%(r-l+1);
if (t)
{
rever(l,r);
//先翻转整体,前面变后面,后面变前面
rever(l,l+t-1);
//对前t个位置(也就是从前最后面的t个位置)进行翻转,得到最开始的排列位置
rever(l+t,r);
//对后面的位置进行翻转,相当于没有变化
//例如(1,2,3,4,5)移动2个单位
//先整体翻转得到(5,4,3,2,1),再翻转前两个得到(4,5,3,2,1)
//再翻转后面3个得到(4,5,1,2,3)
}
}
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define N 510000
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define which(x) (ch[fa[x]][1]==x)
#define inf 0xfffffff
int n,m,cnt,root,lp,rp;
char s[11];
int ch[N][2],a[N];
int val[N],ad[N],size[N],rev[N],mn[N],fa[N];
void read(int &x)
{
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
void update(int x)
{
mn[x]=min(mn[ls(x)],mn[rs(x)]);
mn[x]=min(mn[x],val[x]);
size[x]=size[ls(x)]+size[rs(x)]+1;
}
int build(int l,int r)
{
if(l>r)return 0;
int mid=(l+r)>>1,now=++cnt;
if(mid==0||mid==n+1)
val[now]=inf;
else
val[now]=a[mid];
size[now]=1;
ls(now)=build(l,mid-1);
rs(now)=build(mid+1,r);
fa[ls(now)]=fa[rs(now)]=now;
update(now);
return now;
}
void reverse(int x)
{
swap(ls(x),rs(x));
rev[x]^=1;
}
void add(int x,int v)
{
ad[x]+=v;
if(mn[x]!=inf)
mn[x]+=v;
if(val[x]!=inf)
val[x]+=v;
}
void pushdown(int x)
{
if(rev[x])
{
reverse(ls(x));
reverse(rs(x));
rev[x]^=1;
}
if(ad[x])
{
add(ls(x),ad[x]);
add(rs(x),ad[x]);
ad[x]=0;
}
}
void down(int x)
{
if(fa[x])
down(fa[x]);
pushdown(x);
}
void rotate(int x)
{
int y=fa[x],k=which(x);
ch[y][k]=ch[x][k^1],ch[x][k^1]=y;
ch[fa[y]][which(y)]=x;
fa[x]=fa[y];fa[y]=x;
fa[ch[y][k]]=y;
update(y);update(x);
}
void splay(int x,int tar)
{
down(x);
while(fa[x]!=tar)
{
int y=fa[x];
if(fa[y]==tar)rotate(x);
else
{
if(which(x)^which(y))
rotate(x);
else rotate(y);
rotate(x);
}
}
if(tar==0)root=x;
}
int Rank(int x,int k)
{
pushdown(x);
if(size[ls(x)]+1==k) return x;
if(size[ls(x)]+1>k) return Rank(ls(x),k);
return Rank(rs(x),k-size[ls(x)]-1);
}
int get(int l,int r)
{
lp=Rank(root,l),rp=Rank(root,r);
splay(lp,0),splay(rp,lp);
return ls(rp);
}
int main()
{
read(n),mn[0]=inf;
for(int i=1;i<=n;i++) read(a[i]);
root=build(0,n+1);
read(m);
int x,y,T;
while(m--)
{
scanf("%s",s+1);
if(s[1]=='A')
//区间加上一个数字
{
read(x),read(y),read(T),x++,y++;
add(get(x-1,y+1),T);
}
else if(s[1]=='I')
//insert一个数字
{
read(x),read(y);x++;
get(x,x+1);
ch[rp][0]=++cnt;
//将所加入的数字变成rp这个点的左子树
fa[cnt]=rp;
size[cnt]=1;
val[cnt]=mn[cnt]=y;
update(rp);
update(lp);
}
else if(s[1]=='M')
//返回最小值
{
read(x),read(y);x++,y++;
printf("%d\n",mn[get(x-1,y+1)]);
}
else if(s[1]=='D')
//删除一个元素
{
read(x),x++;
get(x-1,x+1);ls(rp)=0;
update(lp),update(rp);
}
else if(s[4]=='E')
//翻转一段元素
{
read(x),read(y),x++,y++;
reverse(get(x-1,y+1));
}
else
{
read(x),read(y),read(T),x++,y++;
T=(T%(y-x+1)+y-x+1)%(y-x+1);
if(!T)
continue;
int p1=Rank(root,y),p2=Rank(root,y+1);
int t=get(x-1,y-T+1);
down(t);
ch[rp][0]=0;
update(rp),update(lp);
splay(p1,0),splay(p2,p1);
down(p2);
ch[p2][0]=t,fa[t]=p2;
update(p2),update(p1);
}
}
}
采用非旋转treap
/*
本题是对一个数列进行操作,于是将数列1到N维护成一个treap
中序遍历时得到1..N
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1210010
using namespace std;
struct Node
{
int ls,rs; int val,key;
int size; int add,rev;
int minn;
}a[N]; int tot;
struct par{int x,y;};
inline void pushup(int x)
{
int ls=a[x].ls,rs=a[x].rs;
a[x].size=1;
a[x].minn=a[x].val;
if(ls)
a[x].size+=a[ls].size,a[x].minn=min(a[x].minn,a[ls].minn);
if(rs)
a[x].size+=a[rs].size,a[x].minn=min(a[x].minn,a[rs].minn);
}
inline void pushdown(int x)
{
int ls=a[x].ls,rs=a[x].rs;
if(a[x].rev)
{
if(ls)
a[ls].rev^=1,swap(a[ls].ls,a[ls].rs);
if(rs)
a[rs].rev^=1,swap(a[rs].ls,a[rs].rs);
a[x].rev=0;
}
if(a[x].add)
{
if(ls)
a[ls].add+=a[x].add,a[ls].minn+=a[x].add,a[ls].val+=a[x].add;
if(rs)
a[rs].add+=a[x].add,a[rs].minn+=a[x].add,a[rs].val+=a[x].add;
a[x].add=0;
}
}
int merge(int x,int y)
//x的编号小,y的编号大
{
if(!x||!y) return x|y;
pushdown(x);
pushdown(y);
if(a[x].key>a[y].key)
{
a[x].rs=merge(a[x].rs,y); pushup(x);
return x;
}
else
{
a[y].ls=merge(x,a[y].ls); pushup(y);
return y;
}
}
par split(int x,int k)
{
if(!k) return (par){0,x};
pushdown(x);
int ls=a[x].ls,rs=a[x].rs;
if(k==a[ls].size)
{
a[x].ls=0;
pushup(x);
return (par){ls,x};
}
else if(k==a[ls].size+1)
{
a[x].rs=0; pushup(x);
return (par){x,rs};
}
else if(k<a[ls].size)
{
par t=split(ls,k);
a[x].ls=t.y; pushup(x);
return (par){t.x,x};
}
else
{
par t=split(rs,k-a[ls].size-1);
a[x].rs=t.x; pushup(x);
return (par){x,t.y};
}
}
inline int newnode(int val)
{
tot++;
a[tot].val=a[tot].minn=val;
a[tot].ls=a[tot].rs=0;
a[tot].size=1;
a[tot].key=rand()*rand();
a[tot].rev=a[tot].add=0;
return tot;
}
inline void update(int x,int val)
{
a[x].add+=val; a[x].minn+=val; a[x].val+=val;
}
inline void rev(int x)
{
a[x].rev^=1; swap(a[x].ls,a[x].rs);
}
int insert(int x,int k,int val)
{
par t=split(x,k);
return merge(t.x,merge(newnode(val),t.y));
}
void output(int x)
{
int ls=a[x].ls,rs=a[x].rs;
if(ls) output(ls);
printf("%d ",a[x].val);
if(rs) output(rs);
}
int main()
{
// freopen("1895.in","r",stdin);
// freopen("1895.out","w",stdout);
srand(19260817);
int n; cin >> n ;
int root=1;
int x;
scanf("%d",&x);
root=newnode(x);
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
root=merge(root,newnode(x));
}
int y,z; char opt[100];
int m;
cin >> m ;
for(int i=1;i<=m;i++)
{
scanf("%s",opt+1);
if(opt[1]=='A')
{
scanf("%d%d",&x,&y);
par t1=split(root,x-1);
par t2=split(t1.y,y-x+1);
scanf("%d",&z);
update(t2.x,z);
root=merge(t1.x,merge(t2.x,t2.y));
}
else if(opt[1]=='R'&&opt[4]=='E')
{
scanf("%d%d",&x,&y);
par t1=split(root,x-1);
par t2=split(t1.y,y-x+1);
rev(t2.x);
root=merge(t1.x,merge(t2.x,t2.y));
}
else if(opt[1]=='R'&&opt[4]=='O')
{
scanf("%d%d%d",&x,&y,&z);
par t1=split(root,x-1);
par t2=split(t1.y,y-x+1);
par t3=split(t2.x,a[t2.x].size-(z%a[t2.x].size));
root=merge(t1.x,merge(merge(t3.y,t3.x),t2.y));
}
else if(opt[1]=='I')
{
scanf("%d%d",&x,&y);
y=newnode(y);
par t=split(root,x);
root=merge(t.x,merge(y,t.y));
}
else if(opt[1]=='D')
{
scanf("%d",&x);
par t1=split(root,x-1);
par t2=split(t1.y,1);
root=merge(t1.x,t2.y);
}
else if(opt[1]=='M')
{
scanf("%d%d",&x,&y);
par t1=split(root,x-1);
par t2=split(t1.y,y-x+1);
printf("%d\n",a[t2.x].minn);
root=merge(t1.x,merge(t2.x,t2.y));
}
}
return 0;
}
#include<ctime>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define min(a,b) (a<b?a:b)
using namespace std;
typedef pair<int,int> pii;
void read(int &x)
{
char ch;bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar());
if(ok) x=-x;
}
int val[1000010];
struct fhq_tream
{
int root,tot,l[1100000],r[1100000],siz[1100000],fix[1100000],var[1100000],mi[1100000],fa[1100000];
bool fd[1100000];
void biaoji_add(int k,int v)
{
if(k)var[k]+=v,mi[k]+=v,fa[k]+=v;
}
void biaoji_flip(int k)
{
if(k)fd[k]^=1,swap(l[k],r[k]);
}
int New(int x)
{
siz[++tot]=1;
mi[tot]=var[tot]=x;
fix[tot]=rand();
return tot;
}
void updata(int k)
{
siz[k]=siz[l[k]]+siz[r[k]]+1;
mi[k]=min(var[k],min(mi[l[k]],mi[r[k]]));
}
void plant(int &k,int l1,int r1)
//https://img2020.cnblogs.com/blog/1835564/202010/1835564-20201015202853197-1950461884.png
//将树建成如上形态,此时并不满足传统treap的要求,即树根优先级别最高
//但对树做中序访问后,得到原数列的顺序
{
if(l1>r1)return;
int mid=(l1+r1)>>1;
k=New(val[mid]);
plant(l[k],l1,mid-1),plant(r[k],mid+1,r1);
updata(k);
}
void down(int k)
{
if(fa[k])
{
biaoji_add(l[k],fa[k]);
biaoji_add(r[k],fa[k]);
fa[k]=0;
}
if(fd[k])
{
biaoji_flip(l[k]);
biaoji_flip(r[k]);
fd[k]=0;
}
}
pii split(int u,int k)
{
if(k==0)return make_pair(0,u);
if(k==siz[u])return make_pair(u,0);
down(u);
if(k<=siz[l[u]])
{
pii t=split(l[u],k);
l[u]=t.second;
updata(u);
return make_pair(t.first,u);
}
else
{
pii t=split(r[u],k-siz[l[u]]-1);
r[u]=t.first;
updata(u);
return make_pair(u,t.second);
}
}
int merge(int a,int b)
{
if(!a||!b)return a|b;
down(a),down(b);
if(fix[a]>fix[b])
{
r[a]=merge(r[a],b);
updata(a);
return a;
}
else
{
l[b]=merge(a,l[b]);
updata(b);
return b;
}
}
void ins(int x,int v)
{
pii t=split(root,x);
root=merge(t.first,merge(New(v),t.second));
}
void del(int x)
{
pii t1=split(root,x),t2=split(t1.first,x-1);
root=merge(t2.first,t1.second);
}
void add(int l,int r,int v)
{
pii t1=split(root,r),t2=split(t1.first,l-1);
biaoji_add(t2.second,v);
root=merge(merge(t2.first,t2.second),t1.second);
}
void flip(int l,int r)
{
pii t1=split(root,r),t2=split(t1.first,l-1);
biaoji_flip(t2.second);
root=merge(merge(t2.first,t2.second),t1.second);
}
void rev(int l,int r,int t)
{
t%=(r-l+1);
pii t1=split(root,r),t2=split(t1.first,l-1),t3=split(t2.second,r-l+1-t);
//目标区域在t2.second
//以于t2.second从中分出前r-l+1-t个元素,则其后面有t个元素
//将它们倒过来连接即t3.second在前,first在后,完成平移操作
root=merge(merge(t2.first,merge(t3.second,t3.first)),t1.second);
}
int ask_min(int l,int r)
{
pii t1=split(root,r),t2=split(t1.first,l-1);
int ans=mi[t2.second];
root=merge(merge(t2.first,t2.second),t1.second);
return ans;
}
void out(int k)
{
if(!k)return;
down(k);
printf("%d %d %d %d\n",l[k],r[k],var[k],mi[k]);
out(l[k]),out(r[k]);
}
}a;
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
srand(time(0));
int n,m,l,r,v;
char opt[10];
read(n);
for(int i=1;i<=n;i++)
read(val[i]);
a.mi[0]=2e9;
a.plant(a.root,1,n);
//开始时树的根结点为1
read(m);
for(int i=1;i<=m;i++)
{
scanf("%s",opt+1);
if(opt[1]=='A')
//每个元素都加上D
{
read(l),read(r),read(v);
a.add(l,r,v);
}
else if(opt[1]=='I')
//插入P
{
read(l),read(r),
a.ins(l,r);
}
else if(opt[1]=='D')
//删除操作
{
read(l);
a.del(l);
}
else if(opt[1]=='M')
//查询最小值
{
read(l),read(r);
printf("%d\n",a.ask_min(l,r));
}
else if(opt[4]=='E')
//翻转操作
{
read(l),read(r);
a.flip(l,r);
}
else if(opt[4]=='O')
//旋转[l,r]区间v个单位
{
read(l),read(r),read(v);
a.rev(l,r,v);
}
}
return 0;
}

浙公网安备 33010602011771号