zoukankan      html  css  js  c++  java
  • Uva 11996 Jewel Magic (Splay)

    Jewel Magic

    Description

    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).

    Output

    For each type-4 operation, output the answer.

    Explanation:

    String after operation 1 0 1: 1000100001100

    String after operation 3 7 10: 1000101000100

    String after operation 2 9: 100010100100

    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

    Sample Output

    3

    6

    2

    0

    3

    2

    /*
     * UVa 11996 Jewel Magic
     *
     * 给你一个1~n的的01串,进行下面四个操作
     * 1 p c 在第p个字符后面插入c
     * 2 p   删除第p个字符
     * 3 x y 翻转区间[x,y]的字符
     * 4 x y 求从x和y开始的后缀的lcp
     *
     * 前三个都是Splay的基本操作,很容易实现,第四个操作用后缀数组显然不行,考虑用字符串hash
     * 每个节点新增加两个变量,这个子树的hash值和反转的hash值,然后二分长度回答即可
     */
    
    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    
    #define Key_value ch[ch[root][1]][0]
    const int MAXN = 400010;
    const int INF = 0X3F3F3F3F;
    const int MOD = 1000000000+7;
    int fa[MAXN],ch[MAXN][2],key[MAXN],sz[MAXN],rev[MAXN];
    long long ha[MAXN],fha[MAXN];
    long long Hash[MAXN];
    int root,tot1;
    int s[MAXN],tot2;
    char str[MAXN];
    int n,m;
    
    void NewNode(int &r,int pre,int k)
    {
        if(tot2) r=s[tot2--];
        else r=++tot1;
        ch[r][0]=ch[r][1]=0;
        fa[r]=pre;
        sz[r]=1;
        rev[r]=0;
        ha[r]=k;
        fha[r]=k;
        key[r]=k;
    }
    void Update_Rev(int r)
    {
        if(r==0) return;
        swap(ch[r][0],ch[r][1]);
        swap(ha[r],fha[r]);
        rev[r]^=1;
    }
    void Push_Up(int r)
    {
        int lson=ch[r][0],rson=ch[r][1];
        sz[r]=sz[lson]+sz[rson]+1;
        long long lha=ha[lson],rha=ha[rson];
         long long lfha=fha[lson],rfha=fha[rson];
         ha[r]=lha+(key[r]*Hash[sz[lson]])%MOD+(rha*Hash[sz[lson]+1])%MOD;
         ha[r]%=MOD;
         fha[r]=rfha+(key[r]*Hash[sz[rson]])%MOD+(lfha*Hash[sz[rson]+1])%MOD;
         fha[r]%=MOD;
    }
    void Push_Down(int r)
    {
        if(rev[r])
        {
            Update_Rev(ch[r][0]);
            Update_Rev(ch[r][1]);
            rev[r]=0;
        }
    }
    void Build(int &x,int l,int r,int pre)
    {
        if(l>r) return;
        int mid=(l+r)/2;
        NewNode(x,pre,str[mid]-'0');
        Build(ch[x][0],l,mid-1,x);
        Build(ch[x][1],mid+1,r,x);
        Push_Up(x);
    }
    void Init()
    {
        Hash[0]=1;
        for(int i=1;i<MAXN;i++) Hash[i]=(Hash[i-1]*2)%MOD;
        root=tot1=tot2=0;
        ch[root][0]=ch[root][1]=sz[root]=rev[root]=fa[root]=0;
        NewNode(root,0,-1);
        NewNode(ch[root][1],root,-1);
        Build(Key_value,0,n-1,ch[root][1]);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void Rotate(int x,int d)
    {
        int y=fa[x];
        Push_Down(y);
        Push_Down(x);
        ch[y][!d]=ch[x][d];
        fa[ch[x][d]]=y;
        if(fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x;
        fa[x]=fa[y];
        ch[x][d]=y;
        fa[y]=x;
        Push_Up(y);
    }
    void Splay(int r,int goal)
    {
        Push_Down(r);
        while(fa[r]!=goal)
        {
            if(fa[fa[r]]==goal)
            {
                Push_Down(fa[r]);
                Push_Down(r);
                Rotate(r,ch[fa[r]][0]==r);
            }
            else
            {
                Push_Down(fa[fa[r]]);
                Push_Down(fa[r]);
                Push_Down(r);
                int y=fa[r];
                int d=(ch[fa[y]][0]==y);
                if(ch[y][d]==r)
                {
                    Rotate(r,!d);
                    Rotate(r,d);
                }
                else
                {
                    Rotate(y,d);
                    Rotate(r,d);
                }
            }
        }
        Push_Up(r);
        if(goal==0) root=r;
    }
    int Get_Kth(int r,int k)
    {
        Push_Down(r);
        int t=sz[ch[r][0]]+1;
        if(t==k) return r;
        if(t>k) return Get_Kth(ch[r][0],k);
        else return Get_Kth(ch[r][1],k-t);
    }
    void Erase(int r)
    {
        if(r)
        {
            s[++tot2]=r;
            Erase(ch[r][0]);
            Erase(ch[r][1]);
        }
    }
    void update_int(int x,int y)
    {
        Splay(Get_Kth(root,x+1),0);
        Splay(Get_Kth(root,x+2),root);
        NewNode(Key_value,ch[root][1],y);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void update_del(int x)
    {
        Splay(Get_Kth(root,x),0);
        Splay(Get_Kth(root,x+2),root);
        Erase(Key_value);
        fa[Key_value]=0;
        Key_value=0;
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void update_rev(int x,int y)
    {
        Splay(Get_Kth(root,x),0);
        Splay(Get_Kth(root,y+2),root);
        Update_Rev(Key_value);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    bool check(int len,int l,int r)
    {
        Splay(Get_Kth(root,l),0);
        Splay(Get_Kth(root,l+len+1),root);
        long long k1=ha[Key_value];
        Splay(Get_Kth(root,r),0);
        Splay(Get_Kth(root,r+len+1),root);
        long long k2=ha[Key_value];
        return k1==k2;
    }
    int query_lcp(int x,int y)
    {
        int l=0,r=sz[root]-1-y;
        int res;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid,x,y)) l=mid+1,res=mid;
            else r=mid-1;
        }
        return res;
    }
    
    int main()
    {
        int t,x,y,z;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            scanf("%s",str);
            Init();
            while(m--)
            {
                scanf("%d",&t);
                if(t==1)
                {
                    scanf("%d%d",&x,&y);
                    update_int(x,y);
                }
                else if(t==2)
                {
                    scanf("%d",&x);
                    update_del(x);
                }
                else if(t==3)
                {
                    scanf("%d%d",&x,&y);
                    update_rev(x,y);
                }
                else
                {
                    scanf("%d%d",&x,&y);
                    printf("%d
    ",query_lcp(x,y));
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    我的插件架构
    .net 处理图片亮度
    封装自己的对称加密模块
    漏洞无处不在之窃取你的QQ信息
    写自己的自动升级模块
    抓到一只网马,发文顺便鄙视下360
    .net 3.5的Socket异步完成端口
    检测本机是否登录了指定QQ账号
    C++/CLR写的Data Blocks
    修改的Vista风格多功能日历Demo
  • 原文地址:https://www.cnblogs.com/wangdongkai/p/5767011.html
Copyright © 2011-2022 走看看