洛谷P4036 [JSOI2008]火星人——题解

题目传送门
题目大意:
写一个数据结构,需要支持三种操作:
1.单点修改一个字符
2.单点插入一个字符
3.询问两个后缀的LCQ


思考过程:
一开始想到的是后缀数组,但是后缀数组似乎不支持插入的操作。那么能够在小于log的时间内求出LCQ的,也只有hash的 O ( 1 ) 了。而题目又需要提出一段区间来进行操作,所以很容易想到splay。没错,hash+splay就能够完美地解决这道题了。(最近做了好多hash+splay的题。。。)


具体做法:
数据结构题请看代码。


代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn=1.5e5+1000,mod=9875321;
int fa[maxn],c[maxn][2],size[maxn],v[maxn],h[maxn],p[maxn],id[maxn];
char ch[maxn];
int root,m,sz,n;

void pushup(int k)
{
    int l=c[k][0],r=c[k][1];
    size[k]=size[l]+size[r]+1;
    h[k]=h[l]+(long long)v[k]*p[size[l]]%mod+(long long)p[size[l]+1]*h[r]%mod;
    h[k]%=mod;  
}

void rotate(int x)
{
    int y=fa[x],z=fa[y],k=c[y][1]==x,w=c[x][!k];
    c[z][c[z][1]==y]=x,c[y][k]=w,c[x][!k]=y;
    fa[w]=y,fa[y]=x,fa[x]=z;
    pushup(y);pushup(x);    
}

void splay(int x,int tar)
{
    while(fa[x]!=tar)
    {
        int y=fa[x],z=fa[y];
        if(z!=tar) rotate((c[y][1]==x)^(c[z][1]==y)?x:y);
        rotate(x);
    }
    if(tar==0) root=x;
}

void build(int l,int r,int f)
{
    if(l>r) return;
    int now=id[l],last=id[f];
    if(l==r)
    {
        v[now]=h[now]=ch[l]-'a'+1;
        fa[now]=last;size[now]=1;
        if(l<f) c[last][0]=now;
        else c[last][1]=now;
        return; 
    }
    int mid=(l+r)>>1;now=id[mid];
    build(l,mid-1,mid);build(mid+1,r,mid);
    v[now]=ch[mid]-'a'+1;fa[now]=last;pushup(now);
    if(mid<f) c[last][0]=now;
    else c[last][1]=now;
}

int find(int x)
{
    int now=root;
    while(1)
    {
        if(x<=size[c[now][0]]) now=c[now][0];
        else if(x==size[c[now][0]]+1) return now;
        else { x-=size[c[now][0]]+1;now=c[now][1]; }
    }
}

int query(int k,int val)
{
    int x=find(k);int y=find(k+val+1);
    splay(x,0);splay(y,root);
    int z=c[y][0];
    return h[z];    
}

int solve(int x,int y)
{
    int l=1,r=min(sz-x,sz-y)-1,ans=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(query(x,mid)==query(y,mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    return ans;
}

void insert(int k,int val)
{
    int x=find(k+1);int y=find(k+2);
    splay(x,0);splay(y,root);
    int z=++sz;c[y][0]=z,fa[z]=y,v[z]=val;
    pushup(z);pushup(y);pushup(x);
}

int main()
{
    scanf("%s",ch+2);
    n=strlen(ch+2);
    p[0]=1; for(int i=1;i<maxn;i++) p[i]=p[i-1]*27%mod;
    for(int i=1;i<=n+2;i++) id[i]=i;
    build(1,n+2,0);
    sz=n+2;root=(n+3)>>1;
    scanf("%d",&m);
    int x,y;
    char s[10],d[10];
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='Q')
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",solve(x,y));  
        }
        else if(s[0]=='R')
        {
            scanf("%d",&x);
            scanf("%s",d);
            x=find(x+1);
            splay(x,0);
            v[root]=d[0]-'a'+1;
            pushup(root);   
        }
        else 
        {
            scanf("%d",&x);
            scanf("%s",d);
            insert(x,d[0]-'a'+1);   
        }
    }   
    return 0;   
}

猜你喜欢

转载自blog.csdn.net/qq_39662197/article/details/80258113
今日推荐