给出一个初始序列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 ",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 ",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 ",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 ",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 ",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; }