zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
  • 相关阅读:
    mysql 启动不了,报错InnoDB相关
    vue 根据屏幕大小重新加载 echarts
    echarts 图例样式
    canvas 创建的图表,在移动端时,手指触碰,无法上下滑动页面
    uni-app 左上角返回按钮消失
    uni-app 缓存无法读取问题
    hbuider 运行 uni-app PC使用安卓模拟器接口请求错误
    wbstrom 使用git提交代码
    后端路由正常,但页面空白
    算法——RSA算法原理(转)
  • 原文地址:https://www.cnblogs.com/Narh/p/9724878.html
Copyright © 2011-2022 走看看