uva11996 - Jewel Magic 伸展树

Problem J

Jewel Magic

I am a magician. I have a string of emeralds and pearls. I may insert new jewels in the string, or remove old ones. I may even reverse a consecutive part of the string. At anytime, if you point to two jewels and ask me, what is the length of the longest common prefix (LCP) of jewel strings starting from these two jewels, I can answer your question instantly. Can you do better than me?

Formally, you'll be given a string of 0 and 1. You're to deal with four kinds of operations (in the following descriptions, L denotes the current length of the string, and jewel positions are number 1 to L numbered from left to right):

1 p c

Insert a jewel c after position p (0<=p<=L. p=0 means insert before the whole string). c=0 means emerald, c=1 represents pearl.

2 p

Remove the jewel at position p (1<=p<=L).

3 p1 p2

Reverse the part starting from position p1, ending at position p2 (1<=p1 < p2<=L)

4 p1 p2

Output the LCP length of jewel strings starting from p1 and p2 (1<=p1 < p2<=L).

Input

There will be several test cases. The first line of each test case contains an integer n and m (1<=n,m<=200,000), where n is the number of pearls initially, m is the number of operations. The next line contains a 01 string of length n. Each of the next m lines contains an operation. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.

Output

For each type-4 operation, output the answer.

Sample Input

12 9
000100001100
1 0 1
4 2 6
3 7 10
4 1 7
2 9
4 3 11
4 1 9
4 1 7
4 2 3

Output for the Sample Input

3
6
2
0
3
2

  长度为N的0,1串,四种操作。

  1 p c,在第p个字符之后插入字符c。

  2 p ,删除第p个字符,后面的字符往前移。

  3 p1 p2,反转第p1到p2个字符。

  4 p1 p2,输出p1开始和p2开始的两个后缀的LCP。


  首先建立虚拟开始结点和结束结点,root是开始结点,root->ch[1]是结束结点,以root->ch[1]->ch[0]为根建立01串的树,这个可以像线段树那样二分建立。对于1,2,3操作,都用range截出相应的一段操作就行了,对于4操作,可以二分长度L,然后截出(x,x+L)和(y,y+L),判断这两个串相不相等,用hash值来判断比较好,因此对于每个结点我们还需要h1和h2代表以这个结点为根的串的正向hash值和倒过来的hash值,维护的时候根据hash值的定义有h1=ch[0]->h1*powers[ch[1]->s+1]+v*powers[ch[1]->s]+ch[1]->h1,h2=ch[1]->h2*powers[ch[0]->s+1]+v*powers[ch[0]->s]+ch[0]->h2,这样我们只需要比较截出来的两段hash值是否相等,其实只用比较h1就行了,但为了防止冲突发生,把h1和h2都比较一下更保险。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXNODE 105
#define MOD 10000007
#define SIGMA_SIZE 4
typedef long long LL;
using namespace std;

const int MAXN=400020;
unsigned powers[MAXN];

struct Node *null,*pit;
struct Node{
    Node* ch[2];
    int s;
    int flip;
    int v;
    unsigned h1,h2;

    Node(){}
    Node(int v):s(1),flip(0),v(v),h1(v),h2(v){
        ch[0]=ch[1]=null;
    }
    void* operator new(size_t){
        return pit++;
    }
    int cmp(int k) const{
        int d=k-ch[0]->s;
        if(d==1) return -1;
        return d<=0?0:1;
    }
    void maintain(){
        s=ch[0]->s+ch[1]->s+1;
        h1=ch[0]->h1*powers[ch[1]->s+1]+v*powers[ch[1]->s]+ch[1]->h1;
        h2=ch[1]->h2*powers[ch[0]->s+1]+v*powers[ch[0]->s]+ch[0]->h2;
    }
    void reverse(){
        flip^=1;
        swap(ch[0],ch[1]);
        swap(h1,h2);
    }
    void pushdown(){
        if(flip){
            flip=0;
            ch[0]->reverse();
            ch[1]->reverse();
        }
    }
}pool[MAXN];

void init_null(){
    null=new Node();
    null->s=0;
}

void rotate(Node*& o,int d){
    Node* k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}

//k>=1
void splay(Node*& o,int k){
    o->pushdown();
    int d=o->cmp(k);
    if(d==1) k-=o->ch[0]->s+1;
    if(d!=-1){
        Node* p=o->ch[d];
        p->pushdown();
        int d2=p->cmp(k);
        int k2=(d2==0?k:k-p->ch[0]->s-1);
        if(d2!=-1){
            splay(p->ch[d2],k2);
            if(d2==d) rotate(o,d^1);
            else rotate(o->ch[d],d);
        }
        rotate(o,d^1);
    }
}

struct SplaySequence{
    char* s;
    Node* root;

    // update dummy nodes
    //root: dummy min node
    // root->ch[1]: dummy max node
    // root->ch[1]->ch[0]: actual sequence
    void update_dummy(){
        root->ch[1]->maintain();
        root->maintain();
    }

    //[L,R)
    Node* build(int L,int R){
        int mid=L+(R-L)/2;
        Node* o=new Node(s[mid]);
        if(L<mid) o->ch[0]=build(L,mid);
        if(mid+1<R) o->ch[1]=build(mid+1,R);
        o->maintain();
        return o;
    }
    Node* build(char* s){
        this->s=s;
        root=new Node('[');
        root->ch[1]=new Node(']');
        root->ch[1]->ch[0]=build(0,strlen(s));
        update_dummy();
        return root;
    }

    //[L,R) L>=1
Node*& range(int L,int R){
    splay(root,L);
    splay(root->ch[1],R-L+1);
    return root->ch[1]->ch[0];
}

}ss;

int N,M;
char str[MAXN];

int main(){
    freopen("in.txt","r",stdin);
    powers[0]=1;
    for(int i=1;i<MAXN;i++) powers[i]=powers[i-1]*3137;
    while(scanf("%d%d%s",&N,&M,str)!=EOF){
        pit=pool;
        init_null();
        ss.build(str);
        int op,x,y;
        while(M--){
            scanf("%d%d",&op,&x);
            if(op==1){
                scanf("%d",&y);
                ss.range(x+1,x+1)=new Node(y+'0');
                ss.update_dummy();
            }
            else if(op==2){
                ss.range(x,x+1)=null;
                ss.update_dummy();
            }
            else if(op==3){
                scanf("%d",&y);
                ss.range(x,y+1)->reverse();
                ss.update_dummy();
            }
            else{
                scanf("%d",&y);
                //[L,R)
                int L=0,R=ss.root->s-y;
                while(L+1<R){
                    int mid=L+(R-L)/2;
                    unsigned h1=ss.range(x,x+mid)->h1;
                    if(h1==ss.range(y,y+mid)->h1) L=mid;
                    else R=mid;
                }
                printf("%d\n",L);
            }
        }
    }
    return 0;
}



你可能感兴趣的:(uva11996 - Jewel Magic 伸展树)