SuperMemo

题目大意

给出一个序列,要求你支持区间反转,交换相邻区间,添加一个元素和删除一个元素,以及查询区间最小值等操作。

序列之王——splay

对于区间反转,可以类似懒标记传递修改。
添加或删除一个元素都可以通过splay操作使要添加或删除的元素成为叶子节点,然后就很容易添加或修改了
交换相邻区间,相对比较麻烦。
有一个机智的做法,利用反转来实现,
假如我们要交换[a,b]和[b+1,c]两个区间,其实也就相当于三个反转操作,先反转[a,b]和[b+1,c],再反转[a,c]。

代码

(作为蒟蒻我调试了一个白天)

#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=200000+5;
int i,j,n,m,root;
int a[maxn],tree[maxn][2],num[maxn],bz[maxn],bf[maxn],fa[maxn],q[maxn],s[maxn],cnt;
void update(int x){
    num[x]=min(a[x],min(num[tree[x][0]],num[tree[x][1]]));
    s[x]=s[tree[x][0]]+s[tree[x][1]]+1;
}
int pd(int x){
    if (tree[fa[x]][0]==x) return 0;return 1;
}
void rotate(int x){
    int y=fa[x],z=pd(x),z1=pd(y);
    tree[y][z]=tree[x][1-z];
    if (tree[x][1-z]) fa[tree[x][1-z]]=y;
    if (fa[y]) tree[fa[y]][z1]=x;
    fa[x]=fa[y];
    tree[x][1-z]=y;fa[y]=x;
    update(y);
}
void ch(int x,int y){
    if (x==0) return;
    a[x]+=y;num[x]+=y;bz[x]+=y;
}
void clear(int x){
    if (bz[x]){
        ch(tree[x][0],bz[x]);
        ch(tree[x][1],bz[x]); 
    } 
    if (bf[x]){
        bf[x]=0;
        int l=tree[x][0],r=tree[x][1];
        if (l)bf[l]=!bf[l];
        if (r)bf[r]=!bf[r];
        swap(tree[x][0],tree[x][1]);
    }
    bf[x]=bz[x]=0;
}
void chu(int x,int y){
    q[0]=0;
    while (x!=y){
        q[++q[0]]=x;
        x=fa[x];
    }
    int i;
    fod(i,q[0],1) clear(q[i]);
}
void splay(int x,int y){
    chu(x,y);
    while (fa[x]!=y){
        int f=fa[x];
        if (fa[f]!=y)
        if (pd(f)==pd(x)) rotate(f);else rotate(x);
        rotate(x);
    }
    update(x);
    if (!y) root=x;
}   
int kth(int x,int k){
    clear(x); 
    if (s[tree[x][0]]+1==k) return x;
    if (s[tree[x][0]]+1>k) return kth(tree[x][0],k);else
    return kth(tree[x][1],k-s[tree[x][0]]-1);
}
void fan(int x,int y){
    if (x==y) return;
    x=kth(root,x);
    y=kth(root,y+2);
    splay(x,0);
    splay(y,x);
    bf[tree[y][0]]=!bf[tree[y][0]];
}
void ins(int x,int y){
    int w=kth(root,x+1),b=kth(root,x+2);
    splay(w,0);splay(b,w);
    tree[b][0]=++cnt;fa[cnt]=b;num[cnt]=a[cnt]=y;s[cnt]=1;
    update(b);update(w);
}
void del(int x){
    int w=kth(root,x),b=kth(root,x+2);
    splay(w,0);splay(b,w);
    tree[b][0]=0;
    update(b);update(w);
}
int main(){
    while (~scanf("%d",&n)){
        a[0]=a[n+1]=a[n+2]=num[0]=num[n+1]=num[n+2]=maxn*1000;
        memset(tree,0,sizeof(tree));
        s[n+1]=s[n+2]=1;
        fo(i,1,n) {
            scanf("%d",&a[i]);
            if (i>1) tree[i][0]=i-1,fa[i-1]=i;
            else tree[1][0]=n+1,fa[n+1]=1;
            update(i);
        }
        tree[n+2][0]=n,fa[n]=n+2;
        update(n+2);
        cnt=n+2;
        splay(1,0);root=1;
        scanf("%d",&m);
        fo(i,1,m){
            int x,y,t,d;char c;
            c=getchar();
            while ((c<'A')||(c>'Z')) c=getchar();
                if (c=='A') {
                t=1;
                fo(j,1,2) c=getchar();
            }else if (c=='R'){
                fo(j,1,6) {
                    c=getchar();
                    if (j==3)
                    if (c=='E') t=2;else t=3;
                }
            }else if (c=='I'){
                t=4;fo(j,1,5) c=getchar();
            }else if (c=='D'){
                t=5;fo(j,1,5) c=getchar();
            }else {
                t=6;fo(j,1,2) c=getchar();
            }if (t==1){
                scanf("%d%d%d",&x,&y,&d);
                x=kth(root,x);
                y=kth(root,y+2);
                splay(x,0);
                splay(y,x);
                ch(tree[y][0],d);
                update(y);
                update(x);
            }if (t==2){
                scanf("%d%d",&x,&y);fan(x,y);
            }if (t==3){
                scanf("%d%d%d",&x,&y,&d);
                int l=y-x+1;
                d=(d%l+l)%l;
                if (d) fan(x,y-d),fan(y-d+1,y),fan(x,y);
            }if (t==4){
                scanf("%d%d",&x,&y);
                ins(x,y);
            }if (t==5){
                scanf("%d",&x);del(x);
            }if (t==6){
                scanf("%d%d",&x,&y);
                x=kth(root,x);
                y=kth(root,y+2);
                splay(x,0);
                splay(y,x);
                printf("%d\n",num[tree[y][0]]);
            }
        } 
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
舍得制作的“语音版星火考研”词库For SuperMemo 2006版,直接新建一个SuperMemo词库,导入后即可使用。该词汇表源自网上流传的一个星火考研词汇版本,共计收入单词3536个,本词库利用外挂的语音库可以实现自动语音功能,具体方法如下: 1.下载外挂语音库,下载地址及更详尽的使用方法请看这里:http://blog.sina.com.cn/s/blog_5f2d67f90100d97d.html 2.在D盘下新建一个“Speech”文件夹,将下载好语音库解压到这个文件夹中。如果你不想放到D盘,请修改“雅思词汇导入.txt"文件,将”file:///d:/“中的”d“替换成你想要的其他盘符。(包括文件夹也可以改,但你得熟悉这些基本的电脑操作)。 3.本压缩包中带有音标字体Ksphonet.TTF。如果音标不能正常显示,需要安装该字体:1)打开控制面板-字体;2)打开菜单"文件->安装新字体";3)选择Ksphonet.TTF存放的文件夹,安装该字体。   附:词库导入方法:   1.先新建一个库,点击“File->New collection”:   2.检查一下文件保存的位置,一般建议放在默认的“SuperMemo2006”的“Systems”文件夹下(当然放到其他地方也没关系)。在弹出的对话框里填上一个好记的文件名,点击“OK”后继续,这样一个空库就建好了。   3.接下来开始导入,点击菜单“File->Import->Q&A txt”。(如果你的“File”菜单里没有“Import”这一项,那你需要到“File->Level”下打开“Professional”这一级别,“Import”菜单项就会出现了。   然后打开刚才解压出来的词库文件(文本格式),在出现的对话框中,默认选项不用修改,点击OK继续。(Tips:如果这时发现选择的文件不对,可以点击对话框中的“choose file to import”按钮返回重选。)   系统开始转换词库,对话框中的“time expected”就是系统预估所需的转换时间,象舍得导入一个500多K大的词库文件,大约需要1分20多秒的样子。   建好后,系统自动返回主界面。然后我们就可以点击“File->Open Collection”,   选择我们刚才建好的词库,点击界面左下角的“Learn ”按钮,开始我们的学习吧。    详尽的词库导入图文教程请打开下面这个链接进行阅览:  http://blog.sina.com.cn/s/blog_5f2d67f90100d07a.html  http://blog.sina.com.cn/learningpower

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值