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;
}

  

posted @ 2020-10-19 21:42  我微笑不代表我快乐  阅读(106)  评论(0编辑  收藏  举报