UVA 11996 Jewel Magic (splay求兩個後綴的LCP)

題目鏈接

題意:一個長度爲n的01串(n<=200000),m次操作,操作包括在某個位置添加一個字符,刪除某個位置的字符,翻轉某個區間的字符串,詢問兩個後綴的LCP。

題解:對於一個靜態的字符串,詢問其兩個後綴的最長LCP,可以用hash+二分的方法,O(lgn)的複雜度求解一次詢問。

此題對字符串有添加、刪除和區間的翻轉的操作,所以我們考慮用splay維護串的hash值。

具體而言,我們維護以這個點爲根的子樹的點的個數和對應串的hash值。對於區間翻轉操作而言,僅僅維護這些值是不行的,我還要維護以這個點爲根的子樹的翻轉串的hash值。

詳情見代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<string.h>
#include<string>
#include<stdlib.h>
typedef long long LL;
typedef unsigned long long LLU;
const int nn=410000;
const int inf=0x3fffffff;
const LL inf64=(LL)inf*inf;
const int mod=1000000007;
using namespace std;
int n,m;
LL po[nn];
char s[nn];
struct node
{
    int val;
    int cnt;
    LL ha;
    LL fha;
    bool fz;
    node* pre;
    node* ch[2];
}*root;
void init()
{
    po[0]=1;
    for(int i=1;i<=400010;i++)
    {
        po[i]=(po[i-1]*2)%mod;
    }
    root=NULL;
    root=new node;
    root->val=0;
    root->cnt=2;
    root->fz=false;
    root->ha=root->fha=0;
    root->pre=NULL;
    root->ch[0]=root->ch[1]=NULL;

    root->ch[1]=new node;
    root->ch[1]->val=0;
    root->ch[1]->cnt=1;
    root->ch[1]->fz=false;
    root->ch[1]->ha=root->ch[1]->fha=0;
    root->ch[1]->pre=root;
    root->ch[1]->ch[0]=root->ch[1]->ch[1]=NULL;
}
inline void push_up(node* o)
{
    o->cnt=1;
    int lson,rson;
    lson=rson=0;
    LL lha,rha,lfha,rfha;
    lha=rha=lfha=rfha=0;
    if(o->ch[0]!=NULL)
    {
        lha=o->ch[0]->ha;
        lfha=o->ch[0]->fha;
        o->cnt+=o->ch[0]->cnt;
        lson+=o->ch[0]->cnt;
    }
    if(o->ch[1]!=NULL)
    {
        rha=o->ch[1]->ha;
        rfha=o->ch[1]->fha;
        o->cnt+=o->ch[1]->cnt;
        rson+=o->ch[1]->cnt;
    }
    o->ha=lha+(o->val*po[lson])%mod+(rha*po[lson+1])%mod;
    o->ha%=mod;

    o->fha=rfha+(o->val*po[rson])%mod+(lfha*po[rson+1])%mod;
    o->fha%=mod;
}
inline void push_down(node* o)
{
    if(o->fz)
    {
        o->fz=false;
        if(o->ch[0]!=NULL)
        {
            o->ch[0]->fz=!o->ch[0]->fz;
            swap(o->ch[0]->ha,o->ch[0]->fha);
            swap(o->ch[0]->ch[0],o->ch[0]->ch[1]);
        }
        if(o->ch[1]!=NULL)
        {
            o->ch[1]->fz=!o->ch[1]->fz;
            swap(o->ch[1]->ha,o->ch[1]->fha);
            swap(o->ch[1]->ch[0],o->ch[1]->ch[1]);
        }
    }
}
void Rotate(node* o)
{
    node* x=o->pre;
//    push_down(x);
//    push_down(o);
    int d=(x->ch[0]==o)?0:1;
    x->ch[d]=o->ch[d^1];
    if(o->ch[d^1]!=NULL)
    {
        o->ch[d^1]->pre=x;
    }
    if(x->pre!=NULL)
    {
        if(x->pre->ch[0]==x)
            x->pre->ch[0]=o;
        else
            x->pre->ch[1]=o;
    }
    o->pre=x->pre;
    o->ch[d^1]=x;
    x->pre=o;
    push_up(x);
}
void Splay(node* o,node* f)
{
    node* x;
    node* y;
    while(o->pre!=f)
    {
        if(o->pre->pre==f)
            Rotate(o);
        else
        {
            x=o->pre;
            y=x->pre;
            int d1=(y->ch[0]==x)?0:1;
            int d2=(x->ch[0]==o)?0:1;
            if(d1==d2)
            {
                Rotate(x);
                Rotate(o);
            }
            else
            {
                Rotate(o);
                Rotate(o);
            }
        }
    }
    push_up(o);
    if(f==NULL)
        root=o;
}
void select(int k,node* f)
{
    node* o=root;
    int tem;
    while(k)
    {
        push_down(o);
        tem=0;
        if(o->ch[0]!=NULL)
            tem+=o->ch[0]->cnt;
        if(tem>=k)
            o=o->ch[0];
        else if(tem+1==k)
            break;
        else
        {
            o=o->ch[1];
            k-=tem+1;
        }
    }
    Splay(o,f);
}
void build(node* &o,node* f,int l,int r)
{
    int mid=(l+r)/2;
    o=new node;
    o->val=s[mid]-'0';
    o->cnt=1;
    o->ha=o->fha=o->val;
    o->fz=false;
    o->pre=f;
    o->ch[0]=o->ch[1]=NULL;
    if(l<=mid-1)
    {
        build(o->ch[0],o,l,mid-1);
    }
    if(mid+1<=r)
    {
        build(o->ch[1],o,mid+1,r);
    }
    push_up(o);
}
void add(int id,int val)
{
    select(id+1,NULL);
    select(id+2,root);
    root->ch[1]->ch[0]=new node;
    root->ch[1]->ch[0]->val=val;
    root->ch[1]->ch[0]->cnt=1;
    root->ch[1]->ch[0]->ha=root->ch[1]->ch[0]->fha=val;
    root->ch[1]->ch[0]->fz=false;
    root->ch[1]->ch[0]->pre=root->ch[1];
    root->ch[1]->ch[0]->ch[0]=root->ch[1]->ch[0]->ch[1]=NULL;
    Splay(root->ch[1]->ch[0],NULL);
}
void san(int id)
{
    select(id,NULL);
    select(id+2,root);
    delete root->ch[1]->ch[0];
    root->ch[1]->ch[0]=NULL;
    Splay(root->ch[1],NULL);
}
void Reverse(int l,int r)
{
    select(l,NULL);
    select(r+2,root);
    node* &o=root->ch[1]->ch[0];
    o->fz=!o->fz;
    swap(o->ha,o->fha);
    swap(o->ch[0],o->ch[1]);
    push_down(o);
    Splay(o,NULL);
}
bool check(int len,int L,int R)
{
    select(L,NULL);
    select(L+len+1,root);
    LL ix=root->ch[1]->ch[0]->ha;
    select(R,NULL);
    select(R+len+1,root);
    LL fc=root->ch[1]->ch[0]->ha;
    return ix==fc;
}
int solve(int L,int R)
{
    int l=0,r=root->cnt-1-R;
    int mid;
    while(l<r)
    {
        mid=(l+r+1)/2;
        if(check(mid,L,R))
            l=mid;
        else
            r=mid-1;
    }
    return l;
}
void Clear(node* &o)
{
    if(o==NULL)
        return ;
    Clear(o->ch[0]);
    Clear(o->ch[1]);
    delete o;
    o=NULL;
}
int main()
{
    init();
    int ix,p1,p2;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        scanf("%s",s);
        select(1,NULL);
        build(root->ch[1]->ch[0],root->ch[1],0,n-1);
        Splay(root->ch[1]->ch[0],NULL);
        while(m--)
        {
            scanf("%d",&ix);
            if(ix==1)
            {
                scanf("%d%d",&p1,&p2);
                add(p1,p2);
            }
            else if(ix==2)
            {
                scanf("%d",&p1);
                san(p1);
            }
            else if(ix==3)
            {
                scanf("%d%d",&p1,&p2);
                Reverse(p1,p2);
            }
            else
            {
                scanf("%d%d",&p1,&p2);
                printf("%d\n",solve(p1,p2));
            }
        }
        select(1,NULL);
        select(root->cnt,root);
        Clear(root->ch[1]->ch[0]);
        Splay(root->ch[1],NULL);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章