UVA 11996 Jewel Magic splay+字符串hash

     给一个长度为n的01串,m个操作:

1 p c :在第p位之后插入字符

2 p   :删除第p位字符

3 p1 p2: 把从p1到p2位之间的字符翻转

4 p1 p2: 查询以p1,p2开始的字符串的最长公共前缀。

前三个操作可以直接用伸展树处理,查询lcp的话,可以给在每个节点记录一下该子树表示的字符串的hash值,这样在查询的时候就可以二分长度去求lcp了。

因为涉及到翻转操作,所以要求两个hash值,一个正向一个反向,在翻转的时候,直接交换这两个方向的hash值就行。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull x=233;
const int maxn=502000;
int a[maxn],b[maxn];
char s[maxn];
ull H[2][maxn];
ull xp[maxn];
int size[maxn];
int pre[maxn],ch[maxn][2];
int flip[maxn];
int tot,root;
int n,m;
struct splaytree
{
    void init()
    {
        tot=root=0;
        newnode(root,0,0);
        newnode(ch[root][1],root,0);
        build(1,n,ch[ch[root][1]][0],ch[root][1]);
        pushup(ch[root][1]);
        pushup(root);
    }

    void pushup(int r)
    {
        if (r==0) return;
        size[r]=size[ch[r][0]]+1+size[ch[r][1]];
        H[1][r]=H[1][ch[r][0]]*xp[1+size[ch[r][1]]]+a[r]*xp[size[ch[r][1]]]+H[1][ch[r][1]];
        H[0][r]=H[0][ch[r][0]]+a[r]*xp[size[ch[r][0]]]+H[0][ch[r][1]]*xp[size[ch[r][0]]+1];
    }
    void go_f(int r)
    {
        if (!r) return;

        flip[r]^=1;
        swap(H[0][r],H[1][r]);
        swap(ch[r][0],ch[r][1]);
//        pushup(r);
    }
    void pushdown(int r)
    {
        if (flip[r])
        {
            go_f(ch[r][0]);
            go_f(ch[r][1]);
            flip[r]=0;
        }
    }
    void rotate(int xx,int kind)
    {
        int y=pre[xx];
        pushdown(y);
        pushdown(xx);
        ch[y][!kind]=ch[xx][kind];
        pre[ch[xx][kind]]=y;
        if (pre[y])
        {
            ch[pre[y]][ch[pre[y]][1]==y]=xx;
        }
        pre[xx]=pre[y];
        ch[xx][kind]=y;
        pre[y]=xx;
        pushup(y);
    }
    void splay(int xx,int tgt)
    {
        pushdown(xx);
        while(pre[xx]!=tgt)
        {
            int y=pre[xx];
            if (pre[pre[xx]]==tgt)
            {
                rotate(xx,ch[pre[xx]][0]==xx);
            }
            else
            {
                int kind=(ch[pre[y]][0]==y);
                if (ch[y][kind]==xx)
                {
                    rotate(xx,kind^1);
                    rotate(xx,kind);
                }
                else
                {
                    rotate(y,kind);
                    rotate(xx,kind);
                }
            }
        }
        pushup(xx);
        if (tgt==0) root=xx;
    }
    void select(int k,int tgt)
    {
        int rt=root;
        pushdown(rt);
        while(true)
        {
            if (k<=size[ch[rt][0]]) rt=ch[rt][0];
            else if (k==size[ch[rt][0]]+1) break;
            else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];
            pushdown(rt);
        }
        splay(rt,tgt);
    }
    void newnode(int &r,int father,int k)
    {
        r=++tot;
        pre[r]=father;
        size[r]=1;
        flip[r]=0;
        a[r]=k;
        H[0][r]=H[1][r]=k;
        ch[r][0]=ch[r][1]=0;
    }
    void build(int l,int r,int &xx,int rt)
    {
        if (l>r) return;
        int m=(l+r)>>1;
        newnode(xx,rt,b[m]);
        build(l,m-1,ch[xx][0],xx);
        build(m+1,r,ch[xx][1],xx);
        pushup(xx);
        pushup(rt);
    }
    void insert(int posi,int c)
    {
        select(posi+1,0);
        select(posi+2,root);
        newnode(ch[ch[root][1]][0],ch[root][1],c);
        pushup(ch[root][1]);
        pushup(root);
    }
    void del(int posi)
    {
        select(posi,0);
        select(posi+2,root);
        int k=ch[ch[root][1]][0];
        pre[k]=0;
        ch[ch[root][1]][0]=0;
        pushup(ch[root][1]);
        pushup(root);
    }
    ull queryHash(int r,int l)
    {
        select(r,0);
        select(r+l+1,root);
        return H[0][ch[ch[root][1]][0]];

    }
    bool check(int p1,int p2,int l)
    {
        if (queryHash(p1,l)==queryHash(p2,l)) return true;
        return false;
    }
    int getlcp(int p1,int p2)
    {

        int ans;
        if (!check(p1,p2,1))
        {
            return 0;
        }
        ans=1;
        int l=1,r=min(size[root]-2-p1+1,size[root]-2-p2+1)+1;
        int mid;
        while(l<r)
        {
            mid=(l+r)>>1;
            if (check(p1,p2,mid)) ans=mid,l=mid+1;
            else r=mid;
        }
        return ans;
    }
    void reverse(int p1,int p2)
    {
        select(p1,0);
        select(p2+2,root);
        go_f(ch[ch[root][1]][0]);
        pushup(ch[root][1]);
        pushup(root);
    }
    void print(int r)
    {

        if (r==0) return;
        pushdown(r);
        print(ch[r][0]);
        cout<<a[r];
        print(ch[r][1]);
    }

    void traval(int x)
    {
        if(x)
        {
            pushdown(x);
            traval(ch[x][0]);
            printf("结点%2d:左儿子 %2d 右儿子 %2d 父节点 %2d size=%2d ,val=%2d, filp=%2d\n",x,ch[x][0],ch[x][1],pre[x],size[x],a[x],flip[x]);
            traval(ch[x][1]);
        }
    }
    void Debug()
    {
        printf("%d\n",root);
        traval(root);
    }

}spt;

void reads(int & x)
{
    char c;
    bool neg=false;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c=='-')
    {
        neg=true;
        while((c=getchar())<'0'||c>'9');
    }
    x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';
    if(neg) x=-x;
}

int main()
{
//    freopen("in.txt","r",stdin);
    xp[0]=1;
    for (int i=1; i<maxn; i++)
    xp[i]=xp[i-1]*x;
    while(~scanf("%d%d",&n,&m))
    {
        scanf("%s",s);
        for (int i=1; i<=n; i++)
        b[i]=s[i-1]-'0';
        spt.init();
//        spt.traval(root);
//        spt.print(root);
//        cout<<endl;
        int cmd,p1,p2,p3,p4;
        while(m--)
        {
//            scanf("%d",&cmd);
            reads(cmd);
            if (cmd==1)
            {
//                scanf("%d%d",&p1,&p2);
                reads(p1); reads(p2);
                spt.insert(p1,p2);
            }
            else if (cmd==2)
            {
//                scanf("%d",&p1);
                reads(p1);
                spt.del(p1);
            }
            else if (cmd==3)
            {
//                scanf("%d%d",&p1,&p2);
                reads(p1); reads(p2);
                spt.reverse(p1,p2);
//                spt.traval(root);
//                cout<<p1<<" "<<p2<<endl;
//                spt.print(root);
//                cout<<endl;
            }
            else if (cmd==4)
            {
//                scanf("%d%d",&p1,&p2);
                reads(p1); reads(p2);
                printf("%d\n",spt.getlcp(p1,p2));
            }
        }
    }
    return 0;
}


你可能感兴趣的:(UVA 11996 Jewel Magic splay+字符串hash)