ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

Phorni 是一个音之妖精,喜欢在你的打字机上跳舞。
一天,阳光映射到刚刚淋浴过小雨的城市上时,Phorni 用魔法分裂出了许多个幻影,从 1 到 n 编号。
她的每一个幻影都站在打出的字符串的一个位置上,多个幻影可以站在同一个位置上。
每一个幻影代表的字符串即为从它站立位置开始的后缀,注意站立位置是从右往左数的。
让我们形式化地描述一下,若第 i 个幻影站在 Pi 上,那么它所代表的字符串就是 S[L-Pi+1…L],其中 L 是字符串 S 的长度。
每一次,她会选一段编号区间 [l..r],而编号在这个区间中的幻影中,字典序最小的一个将跳一支舞,若有多个幻影字典序相同,选编号最小的。
当然由于 Phorni 还会在打字机上跳动,所以有时字符串的前面会加入一个字符。
当然这个打字机是带加密功能的。
字典序的比较:
将两个字符串逐位比较,长度不足的向后补 0 ( 0 小于任何字符) 。直到比出大小或判定相等。
比如 “pho” > “ph” , “pb” > “pab” 。
下标从 1 开始,保证涉及到的所有字符都为小写字母。

Input

输入共 m + 3 行,
第一行为三个整数 n, m, len, type, 分别代表幻影个数,操作次数,初始字符串长度。type = 1 时表示所有的字符都经过了加密。
第二行为初始字符串 S 。
第三行,n 个数 Pi ,意义如题面所示。
接下来 m 行,每行表示一个操作。
1. I c 若 type = 0 表示在字符串前面加入第 c + 1 个小写字母,若 type = 1 则表示加入第 (c xor lastans) + 1 个小写字母,lastans 表示上一次的答案,初始为 0 。
2. C x pos 表示第 x 个幻影跳到了从右向左数 pos 的位置上。
3. Q l r 表示询问[l..r] 。

Output

对于每个询问操作输出一行,表示去跳舞的幻影编号。

用后缀平衡树支持动态O(1)查询后缀间的大小关系,O(logn)插入新后缀,线段树支持查询

后缀平衡树的具体实现:

建一颗含有约262个点的满二叉树,记录其中序遍历标号,用treap维护后缀从小到大排列构成的序列,并维护treap中每个点x对应满二叉树中的点rk[x]作为标号,由于有中序遍历的标号,可以O(1)判断两个点在treap中的先后关系。s[a..n]<s[b..n] 等价于 s[a]<s[b]||s[a]==s[b]&&s[a+1..n]<s[b+1..n] 等价于 rk[a]<rk[b],于是可以支持插入新后缀,新点插入完成后重新暴力计算新点所在子树的标号。由于treap期望重量平衡,可以保证期望O(logn)的插入。由于期望深度较小,treap一般不会超出满二叉树的范围而导致标号失效。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
char buf[30000000],*ptr=buf-1;
void _(int&x){
    x=0;
    int c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
}
void _(char*s){
    int c=*++ptr;
    while(c<33)c=*++ptr;
    while(c>32)*s++=c,c=*++ptr;
    *s=0;
}
typedef long long i64;
int n,m,len,tp,la=0;
char s[300007],op[8];
int sn,tr[1<<20|111],mx,ps[500007];
i64 rk[300007];
int _min(int a,int b){
    i64 z=rk[ps[a]]-rk[ps[b]];
    return (z?z<0:a<b)?a:b;
}
void up(int w){
    int l=w<<1,r=l^1;
    tr[w]=_min(tr[l],tr[r]);
}
struct node{
    node*lc,*rc;
    int id,rnd;
    bool operator<(const node&w)const{
        return s[id]<s[w.id]||s[id]==s[w.id]&&rk[id-1]<rk[w.id-1];
    }
    void split(node*x,node*&l,node*&r){
        if(!this){l=r=0;return;}
        if(*x<*this){
            lc->split(x,l,lc);
            r=this;
        }else{
            rc->split(x,rc,r);
            l=this;
        }
    }
    void rebuild(i64 l,i64 r){
        if(!this)return;
        i64 m=rk[id]=(l+r)>>1;
        lc->rebuild(l,m-1);
        rc->rebuild(m+1,r);
    }
    node*ins(node*w,i64 l,i64 r){
        if(!this||rnd<w->rnd){
            split(w,w->lc,w->rc);
            w->rebuild(l,r);
            return w;
        }
        if(*w<*this)lc=lc->ins(w,l,rk[id]-1);
        else rc=rc->ins(w,rk[id]+1,r);
        return this;
    }
}ns[300007],*rt;
void ins(int w){
    ns[w].id=w;
    ns[w].rnd=rand();
    rt=rt->ins(ns+w,0,1ll<<62);
}
int main(){
    fread(buf,1,sizeof(buf),stdin)[buf]=0;
    rt=ns;
    rt->rebuild(0,1ll<<62);
    _(n);_(m);_(len);_(tp);
    srand(n^m+len^1231+tp);
    _(s+1);
    sn=strlen(s+1);
    std::reverse(s+1,s+sn+1);
    for(int i=1;i<=sn;++i)ins(i);
    for(mx=1;mx<=n+4;mx<<=1);
    for(int i=1;i<=n;++i)_(ps[i]),tr[mx+i]=i;
    for(int i=mx-1;i;--i)up(i);
    while(m--){
        _(op);
        if(*op=='I'){
            int x;
            _(x);
            if(tp)x^=la;
            s[++sn]='a'+x;
            ins(sn);
        }else if(*op=='C'){
            int x,y;
            _(x);_(y);
            ps[x]=y;
            for(int w=mx+x>>1;w;w>>=1)up(w);
        }else{
            int l,r;
            _(l);_(r);
            int ans=tr[mx+l];
            for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){
                if(~l&1)ans=_min(ans,tr[l^1]);
                if(r&1)ans=_min(ans,tr[r^1]);
            }
            printf("%d\n",la=ans);
        }
    }
    return 0;
}

 

posted on 2017-05-19 10:49  nul  阅读(313)  评论(0编辑  收藏  举报