1014. [JSOI2008]火星人平衡树-splay+hash

Posted Refun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1014. [JSOI2008]火星人平衡树-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不超过当前字符串长度

Output

  对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。

Sample Input

madamimadam
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11

Sample Output

5
1
0
2
1

HINT

1、所有字符串自始至终都只有小写字母构成。

2、M<=150,000

3、字符串长度L自始至终都满足L<=100,000

4、询问操作的个数不超过10,000个。

对于第1,2个数据,字符串长度自始至终都不超过1,000

对于第3,4,5个数据,没有插入操作。

 

用splay维护hash值
当前点update的时候就用俩儿子的hash值计算一下字符串(左儿子+x+右儿子)新的hash值
hash一开始被卡了素质三连(模数1e4+7不被卡就有鬼了……)
中途有个变量打错了还过了样例emmm……
喜闻乐见样例是有多弱

 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N (200000+100)
  5 #define MOD (19260817)
  6 using namespace std;
  7 int Val[N],Size[N],Son[N][2],Father[N],Sum[N],hash[N];
  8 int Root,n,m,x,y,p,sz;
  9 char opt[15],ch[15],a[N];
 10 
 11 int Get(int x) {return Son[Father[x]][1]==x;}
 12 void Clear(int x) {Sum[x]=Father[x]=Son[x][0]=Son[x][1]=Size[x]=Val[x]=0;}
 13 
 14 void Update(int x)
 15 {
 16     int l=Son[x][0],r=Son[x][1];
 17     Size[x]=Size[l]+Size[r]+1;
 18     Sum[x]=((long long)Sum[l]*hash[Size[r]+2]%MOD + (long long)Val[x]*hash[Size[r]+1] + Sum[Son[x][1]])%MOD;
 19 }
 20 
 21 void Rotate(int x)
 22 {
 23     int wh=Get(x);
 24     int fa=Father[x],fafa=Father[fa];
 25     Father[fa]=x;
 26     Son[fa][wh]=Son[x][wh^1];
 27     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 28     Father[x]=fafa;
 29     Son[x][wh^1]=fa;
 30     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
 31     Update(fa);
 32     Update(x);
 33 }
 34 
 35 void Splay(int x,int tar)
 36 {
 37     for (int fa; (fa=Father[x])!=tar; Rotate(x))
 38         if (Father[fa]!=tar)
 39             Rotate(Get(fa)==Get(x)?fa:x);
 40     if (!tar) Root=x;
 41 }
 42 
 43 int Findx(int x)
 44 {
 45     int now=Root;
 46     while (1)
 47         if (Size[Son[now][0]]>=x)
 48             now=Son[now][0];
 49         else
 50         {
 51             x-=Size[Son[now][0]];
 52             if (x==1)
 53             {
 54                 Splay(now,0);
 55                 return now;
 56             }
 57             x--;
 58             now=Son[now][1];
 59         }
 60 }
 61 
 62 void Build(int l,int r,int fa)
 63 {
 64     if (l>r) return;
 65     int mid=(l+r)>>1;
 66     Build(l,mid-1,mid);
 67     Build(mid+1,r,mid);
 68     Father[mid]=fa;
 69     Son[fa][mid>fa]=mid;
 70     Val[mid]=a[mid]-a+1;
 71     Update(mid);
 72 }
 73 
 74 int Split(int x,int y)
 75 {
 76     int xx=Findx(x),yy=Findx(y);
 77     Splay(xx,0);
 78     Splay(yy,xx);
 79     return Son[yy][0];
 80 }
 81 
 82 bool check(int len)
 83 {
 84     int xx=Split(x,x+len+1);
 85     int ans1=Sum[xx];
 86     int yy=Split(y,y+len+1);
 87     int ans2=Sum[yy];
 88     return ans1==ans2;
 89 }
 90 
 91 int main()
 92 {
 93     hash[1]=1;
 94     for (int i=2; i<=200000; ++i)
 95         hash[i]=hash[i-1]*27%MOD;
 96 
 97     scanf("%s%d",a+2,&m);
 98     n=strlen(a+2);
 99     Build(1,n+2,0);
100     Root=(n+3)>>1;
101     sz=n+2;
102 
103 
104     for (int i=1; i<=m; ++i)
105     {
106         scanf("%s",opt);
107         if (opt[0]==Q)
108         {
109             scanf("%d%d",&x,&y);
110             int l=1,r=Size[Root]-max(x,y)-1,ans=0;
111             while (l<=r)
112                 if (check((l+r)>>1))
113                 {
114                     l=((l+r)>>1)+1;
115                     ans=l-1;
116                 }
117                 else
118                     r=((l+r)>>1)-1;
119             printf("%d\n",ans);
120         }
121         if (opt[0]==R)
122         {
123             scanf("%d%s",&p,ch);
124             Findx(p+1);
125             Val[Root]=ch[0]-a+1;
126             Update(Root);
127         }
128         if (opt[0]==I)
129         {
130             scanf("%d%s",&p,ch);
131             Split(p+1,p+2);
132             int x=Son[Root][1];
133             Val[++sz]=ch[0]-a+1;
134             Size[sz]=1;
135             Father[sz]=x;
136             Son[x][0]=sz;
137             Splay(sz,0);
138         }
139     }
140 }

以上是关于1014. [JSOI2008]火星人平衡树-splay+hash的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1014 [JSOI2008]火星人prefix

bzoj 1014[JSOI2008]火星人prefix - 二分 + hash + splay

bzoj1014 JSOI2008—火星人prefix

luoguP4036 [JSOI2008]火星人 平衡树+hash

BZOJ1014 [JSOI2008]火星人prefix

bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)