zoukankan      html  css  js  c++  java
  • bzoj1014: [JSOI2008]火星人prefix splay+hash+二分

    Description

      火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,
    我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,
    火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串
    ,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程
    中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,
    如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速
    算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说
    ,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此
    复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。

    Input

      第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操
    作有3种,如下所示
    1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。
    2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字
    符串长度。
    3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字
    符串开头插入。限制:x不超过当前字符串长度

    题解:splay维护区间hash值,每次查询对答案二分,然后O(1)判断相不相等,注意考虑split时l,r为边界的情况
    /**************************************************************
        Problem: 1014
        User: walfy
        Language: C++
        Result: Accepted
        Time:6708 ms
        Memory:7424 kb
    ****************************************************************/
     
    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    //#pragma GCC optimize("unroll-loops")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define fio ios::sync_with_stdio(false);cin.tie(0)
     
    using namespace std;
     
    const double g=10.0,eps=1e-11;
    const int N=100000+10,maxn=5000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
    const ull bs=151;
     
    char a[N];
    ull p[N];
    struct Splay{
        struct Node{
            Node *ch[2];
            int v,s;ull ha;
            int cmp(int x)const{
                int d = x - ch[0]->s;
                if(d==1)return -1;
                return d<=0?0:1;
            }
        };
        inline void maintain(Node *o)
        {
            o->s = 1 + o->ch[0]->s+o->ch[1]->s;
            o->ha = o->v;
            if(o->ch[1]!=null)
            {
                o->ha=o->ha+o->ch[1]->ha*bs;
            }
            if(o->ch[0]!=null)
            {
                o->ha=o->ha*p[o->ch[0]->s]+o->ch[0]->ha;
            }
        }
        Node *null;
        inline void Rotate(Node* &o,int d)
        {
            Node* k = o->ch[d^1];
            o->ch[d^1] = k->ch[d];
            k->ch[d] = o;
            maintain(o);maintain(k);
            o = k;
        }
        inline void splay(Node* &o,int k)
        {
            int d = o->cmp(k);
            if(d==1)k-=o->ch[0]->s+1;
            if(d!=-1)
            {
                Node* p=o->ch[d];
                int d2=p->cmp(k);
                int k2=(d2==0?k:k-p->ch[0]->s-1);
                if(d2!=-1)
                {
                    splay(p->ch[d2],k2);
                    if(d==d2)Rotate(o,d^1);
                    else Rotate(o->ch[d],d);
                }
                Rotate(o,d^1);
            }
        }
        inline Node* Merge(Node* left,Node* right)
        {
            splay(left,left->s);
            left->ch[1]=right;
            maintain(left);
            return left;
        }
        inline void split(Node* o,int k,Node* &left,Node* &right)
        {
            splay(o,k);
            right = o->ch[1];
            o->ch[1]=null;
            left=o;
            maintain(left);
        }
        Node *root,*left,*right;
        inline void init(int sz)
        {
            null = new Node;
            null->s=0;
            root = new Node;
            root->v=(int)a[1]-'a';root->s=1;
            root->ch[0]=root->ch[1]=null;
            maintain(root);
            Node* p;
            for(int i=2;i<=sz;i++)
            {
                p = new Node;
                p->v=a[i]-'a';p->s=0;
                p->ch[0]=root;p->ch[1]=null;
                root=p;
                maintain(root);
            }
    //        debug(root);
        }
        inline void ins()
        {
            int x;char c[5];
            scanf("%d%s",&x,c);
            Node* p=new Node;
            p->v=(int)(c[0]-'a');p->s=1;
            p->ch[0]=p->ch[1]=null;
            if(x==0)
            {
                root=Merge(p,root);
            }
            else
            {
                split(root,x,left,right);
                root=Merge(Merge(left,p),right);
            }
        }
        inline ull getans(int l,int r)
        {
            ull ans=0;
            if(l==1&&r==root->s)ans=root->ha;
            else if(l==1)
            {
                split(root,r,left,right);
                ans=left->ha;
                root=Merge(left,right);
            }
            else if(r==root->s)
            {
                split(root,l-1,left,right);
                ans=right->ha;
                //printf("%lld
    ",right->ha);
                root=Merge(left,right);
            }
            else
            {
                split(root,r,left,right);
                Node *tel,*ter;
                split(left,l-1,tel,ter);
                ans=ter->ha;
                root=Merge(Merge(tel,ter),right);
            }
            //printf("%d %d %lld
    ",l,r,ans);
            return ans;
        }
        inline void query()
        {
            int x,y;scanf("%d%d",&x,&y);
            if(x>y)swap(x,y);
            int n=root->s;
            int l=0,r=n-y+2;
            while(l<r-1)
            {
                //printf("%d %d %lld %d %d %lld
    ",x,x+m-1,getans(x,x+m-1),y,y+m-1,getans(y,y+m-1));
                int m=(l+r)>>1;
                ull te1=getans(x,x+m-1),te2=getans(y,y+m-1);
                if(te1==te2)l=m;
                else r=m;
            }
            printf("%d
    ",l);
        }
        inline void debug(Node* o)
        {
            if(o->ch[0]!=null)debug(o->ch[0]);
            printf("%d %lld %d
    ",o->v,o->ha,o->s);
            if(o->ch[1]!=null)debug(o->ch[1]);
        }
    }sp;
    int main()
    {
        p[0]=1;
        for(int i=1;i<N;i++)p[i]=p[i-1]*bs;
        scanf("%s",a+1);
        int len=strlen(a+1);
    //    for(int i=1;i<=len;i++)printf("%d ",a[i]-'a');puts("");
        sp.init(len);
        int m;scanf("%d",&m);
        while(m--)
        {
            char op[5];
            scanf("%s",op);
            if(op[0]=='Q')sp.query();
            else if(op[0]=='R')
            {
                int x;char c[5];
                scanf("%d%s",&x,c);
                sp.split(sp.root,x,sp.left,sp.right);
                sp.left->v=(int)c[0]-'a';
                sp.root=sp.Merge(sp.left,sp.right);
            }
            else sp.ins();
        }
        return 0;
    }
    /***********************
    998244353
    ***********************/
    
    View Code
  • 相关阅读:
    Win7旗舰版中的IIS配置asp.net的运行环境
    选中弹出层中内容
    在windows server 2003中配置ipad測試環境
    TFS 2012 Preview Quickstart
    Windows Azure Quick Start Hello World
    2013总结 和2014期望
    一个简单的.net写日志方法 可能的改进点
    基于Visual Studio的软件生命周期管理和持续交付 (二) 采用成熟度
    关于加班的那些事
    基于Visual Studio的软件生命周期管理和持续交付 (一) 前言
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/8999427.html
Copyright © 2011-2022 走看看