bzoj 1014 [JSOI2008]火星人prefix——splay+哈希

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014

用splay维护字符串,每个点记录子树的哈希值,然后二分查询。

二分不是把两个点的哈希值拿出来二分!因为取模了所以不能还原;因为splay维护了字符串,所以二分答案后把对应一段转出来看看哈希值一不一样就行了。

如果一开始不是用给出的序列直接建一个树(就是递归 l,mid-1 和 mid+1,r 那样的),而是像我一开始一样一个一个往进插入的话,不知为何过不了呢。

有些卡时间。据说%mod会T,于是用 unsigned long long 自然溢出。

用 nxt 找后继的时候要先把对象旋转到根才行。

幂也要预处理以防超时。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll unsigned long long
using namespace std;
const int N=2e5+5,base=27;
int n,tot,c[N][2],fa[N],rt,siz[N];
ll val[N],sm[N],pw[N];
char ch[N];
int init()
{
    pw[0]=1;
    for(int i=1;i<=N-5;i++) pw[i]=pw[i-1]*base;
}
void pshp(int cr)
{
    int ls=c[cr][0],rs=c[cr][1];
    siz[cr]=siz[ls]+siz[rs]+1;
    
    val[cr]=(val[rs]*base+sm[cr])*pw[siz[ls]]+val[ls];
}
void rotate(int x,int &k)
{
    int y=fa[x],z=fa[y];
    if(y==k) k=x;
    else c[z][y==c[z][1]]=x;
    int d=(x==c[y][1]);
    fa[x]=z; fa[y]=x; fa[c[x][!d]]=y;
    c[y][d]=c[x][!d]; c[x][!d]=y;
    pshp(y); pshp(x);
}
void splay(int x,int &k)
{
    while(x!=k)
    {
        int y=fa[x],z=fa[y];
        if(y!=k)
        {
            if((x==c[y][0])^(y==c[z][0]))
                rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
}
int find(int p)
{
    int cr=rt;
    while(cr)
    {
        if(siz[c[cr][0]]+1==p)return cr;
        else if(siz[c[cr][0]]+1<p)
        {
            p-=siz[c[cr][0]]+1;
            cr=c[cr][1];
        }
        else cr=c[cr][0];
    }
}
int nxt(int cr)
{
    cr=c[cr][1];
    while(c[cr][0]) cr=c[cr][0];
    return cr;
}
void insert(int p,int v)
{
    int d=find(p); splay(d,rt);
    int x=nxt(d);  splay(x,c[rt][1]);
    siz[++tot]=1; val[tot]=sm[tot]=v;
    fa[tot]=x;  c[x][0]=tot;
    pshp(x);  pshp(d);
}
void mdfy(int p,int v)
{
    int d=find(p); splay(d,rt);
    sm[d]=v; pshp(d);
}
ll cz(int u,int v)
{
    splay(u,rt);
    int k=find(v);
    splay(k,c[rt][1]);
    return val[c[k][0]];
}
void query(int u,int v)
{
    int l=1,r=min(tot-u,tot-v);
    int ans=0;
    int x=find(u-1), y=find(v-1);
    while(l<=r)
    {
        int mid=l+r>>1;
        if(cz(x,u+mid)==cz(y,v+mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
}
void build(int l,int r,int lst,bool fx)
{
    if(l>r) return;
    int mid=l+r>>1;
    int cr=++tot; fa[cr]=lst; c[lst][fx]=cr;
    sm[cr]=ch[mid]-'a'+1;
    if(l==r) {val[cr]=sm[cr]; siz[cr]=1; return;}
    build(l,mid-1,cr,0); build(mid+1,r,cr,1);
    pshp(cr);
}
int main()
{
    init();
    scanf("%s",ch+2); n=strlen(ch+2);
    ch[1]='a'; ch[n+2]='a'; n+=2;
    build(1,n,0,0); rt=1; c[0][0]=0;
    scanf("%d",&n);
    for(int i=1,x,d;i<=n;i++)
    {
        cin>>ch[0];
        if(ch[0]=='I')
        {
            scanf("%d %c",&x,&ch[1]);
            d=ch[1]-'a'+1; insert(x+1,d);
        }
        if(ch[0]=='R')
        {
            scanf("%d %c",&x,&ch[1]);
            d=ch[1]-'a'+1; mdfy(x+1,d);
        }
        if(ch[0]=='Q')
        {
            scanf("%d%d",&x,&d);
            query(x+1,d+1);
        }
    }
    return 0;
}

 

posted on 2018-09-29 17:24  Narh  阅读(92)  评论(0编辑  收藏  举报

导航