bzoj 1014 splay维护hash值

被后缀三人组虐了一下午,写道水题愉悦身心。

题很裸,求lcq时二分下答案就行了,写的不优美会被卡时。

(写题时精神恍惚,不知不觉写了快两百行。。。竟然调都没调就A了。。。我还是继续看后缀自动机吧。。。)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define bas 131
  6 #define p 1000000007
  7 #define N 100005
  8 #define ll long long
  9 using namespace std;
 10 char c[100005];
 11 int n;
 12 int cnt,root;
 13 int ch[N][2],fa[N],size[N];
 14 ll pow[N],k[N];
 15 ll zi[N];
 16 ll sum[N];
 17 void push_up(int x)
 18 {
 19     size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
 20     k[x]=k[ch[x][1]]+zi[x]*pow[size[ch[x][1]]]+k[ch[x][0]]*pow[size[ch[x][1]]+1];
 21     k[x]%=p;
 22 }
 23 void rotate(int pp)
 24 {
 25     int q=fa[pp],y=fa[q],x=(ch[q][1]==pp);
 26     ch[q][x]=ch[pp][x^1];fa[ch[q][x]]=q;
 27     ch[pp][x^1]=q;fa[q]=pp;
 28     fa[pp]=y;
 29     if(y)
 30     {
 31         if(ch[y][0]==q)ch[y][0]=pp;
 32         else ch[y][1]=pp;
 33     }
 34     push_up(q);
 35 }
 36 void splay(int x)
 37 {
 38     for(int y;y=fa[x];rotate(x))
 39     {
 40         if(fa[y])
 41         {
 42             if((ch[fa[y]][0]==y&&ch[y][0]==x)||(ch[fa[y]][1]==y&&ch[y][1]==x))rotate(y);
 43             else rotate(x);
 44         }
 45     }
 46     push_up(x);
 47     root=x;
 48 }
 49 int find(int x,int kk)
 50 {
 51     if(size[ch[x][0]]+1==kk)return x;
 52     if(size[ch[x][0]]+1>=kk)return find(ch[x][0],kk);
 53     return find(ch[x][1],kk-size[ch[x][0]]-1);
 54 }
 55 ll pp(int x,int l)
 56 {
 57     int r=l+x-1;
 58     if(l!=1)
 59     {
 60         int y=find(root,l-1);
 61         splay(y);
 62         if(r==size[root])
 63         {
 64             return k[ch[y][1]];
 65         }
 66         else
 67         {
 68             fa[ch[y][1]]=0;
 69             int z=find(root,r+1);
 70             splay(z);
 71             fa[z]=y;root=y;ch[y][1]=z;
 72             return k[ch[z][0]];
 73         }
 74     }
 75     else
 76     {
 77         if(r==size[root])return k[root];
 78         splay(find(root,r+1));
 79         return k[ch[root][0]];
 80     }
 81 }
 82 bool pan(int x,int l,int r)
 83 {
 84     if(!x)return 1;
 85     ll t1=pp(x,l),t2=pp(x,r);
 86     if(t1==t2)return 1;
 87     return 0;
 88 }
 89 int main()
 90 {
 91     scanf("%s",c);
 92     n=strlen(c);pow[0]=1;
 93     for(int i=1;i<=100000;i++)pow[i]=(pow[i-1]*bas)%p;
 94     for(int i=0;i<n;i++)
 95     {
 96         sum[i+1]=sum[i]*bas+c[i]-‘a‘+1;
 97         sum[i+1]%=p;
 98     }
 99     root=1;cnt=1;k[1]=sum[n];size[1]=n;zi[1]=c[n-1]-‘a‘+1;
100     for(int i=n-1;i>=1;i--)
101     {
102         cnt++;fa[cnt]=cnt-1;
103         ch[cnt-1][0]=cnt;
104         k[cnt]=sum[i];
105         size[cnt]=i;
106         zi[cnt]=c[i-1]-‘a‘+1;
107     }
108     splay(cnt);
109     int m;
110     scanf("%d",&m);
111     char t[2];int t1,t2;
112     while(m--)
113     {
114         scanf("%s",t);
115         if(t[0]==‘I‘)
116         {
117             scanf("%d",&t1);scanf("%s",t);
118             if(t1!=0)
119             {
120                 int y=find(root,t1);
121                 splay(y);
122                 if(ch[y][1]!=0)
123                 {
124                     int tmp=ch[y][1];
125                     while(ch[tmp][0])tmp=ch[tmp][0];
126                     fa[ch[y][1]]=0;
127                     splay(tmp);
128                     root=y;
129                     ch[y][1]=tmp;
130                     fa[tmp]=y;
131                     ch[tmp][0]=++cnt;
132                     fa[cnt]=tmp;
133                     k[cnt]=t[0]-‘a‘+1;
134                     zi[cnt]=t[0]-‘a‘+1;
135                     size[cnt]=1;
136                     push_up(tmp);
137                 }
138                 else
139                 {
140                     ch[y][1]=++cnt;
141                     fa[cnt]=y;
142                     k[cnt]=t[0]-‘a‘+1;
143                     zi[cnt]=t[0]-‘a‘+1;
144                     size[cnt]=1;
145                 }
146                 push_up(y);
147             }
148             else
149             {
150                 int y=find(root,1);
151                 splay(y);
152                 ch[y][0]=++cnt;
153                 fa[cnt]=y;
154                 k[cnt]=t[0]-‘a‘+1;
155                 zi[cnt]=t[0]-‘a‘+1;
156                 size[cnt]=1;
157                 push_up(y);
158             }
159         }
160         else if(t[0]==‘Q‘)
161         {
162             scanf("%d%d",&t1,&t2);if(t1>t2)swap(t1,t2);
163             int l=0;int r=size[root]-t2+1;
164             while(l<=r)
165             {
166                 int mid=(l+r)>>1;
167                 if(pan(mid,t1,t2))l=mid+1;
168                 else r=mid-1;
169             }
170             printf("%d\n",r);
171         }
172         else
173         {
174             scanf("%d",&t1);scanf("%s",t);
175             int y=find(root,t1);
176             splay(y);
177             k[y]-=zi[y]*pow[size[ch[y][1]]];
178             k[y]+=(t[0]-‘a‘+1)*pow[size[ch[y][1]]];
179             k[y]=((k[y]%p)+p)%p;
180             zi[y]=t[0]-‘a‘+1;
181         }
182     }
183     return 0;
184 }
时间: 2024-08-10 15:04:04

bzoj 1014 splay维护hash值的相关文章

bzoj 1014 LCP 二分 Hash 匹配

求同一字符串的两个后缀的最长公共前缀. 将字符串按位置放到Splay中维护(每个节点还维护一下该子树的hash),然后二分前缀的长度,用splay计算出指定范围的hash,按hash是否相等来判断是否相同. 一开始是将字符串看成26进制,加上unsigned long long的自然溢出来计算哈希,但这样Wa掉了,改成27进制就AC了,但我还不知道为什么,望明者相告,谢. 1 /***********************************************************

【BZOJ-1014】火星人prefix Splay + 二分 + Hash

1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5852  Solved: 1871[Submit][Status][Discuss] Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d

cf213E 线段树维护hash

链接 https://codeforces.com/contest/213/problem/E 题目大意 给出两个排列a.b,长度分别为n.m,你需要计算有多少个x,使 得\(a_1 + x; a_2 + x; a_3 + x... a_n + x\) 是b 的子序列(不连续的那种). 思路 巧妙啊 暴力直接扫会T 我们构造一个c数组,使得c[b[i]]=i 这样x+1到x+1+n就是一段连续的区间了233 插回去看看他们相对大小是不是和a数组相同 因为不连续所以线段树维护hash值,线段树按照

[BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】

题目链接:BZOJ - 1014 题目分析 求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等. 这里有修改字符和插入字符的操作,所以用 Splay 来维护串的 Hash 值. 一个节点的值就是它的子树表示的字串的 Hash 值. 使用 unsigned long long 然后自然溢出就不需要 mod 了,速度会快很多. 代码 #include <iostream> #include <cstd

bzoj 1014 [JSOI2008]火星人prefix(splay+hash)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1014 [题意] 给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP的功能. [思路]  splay维护字符串的哈希值.因为要提供区间,splay采用先查找后调整至根的写法. 一个结点的hash值为: ch[0]->h * X^(ch[1]->s+1)+v * X^(ch[1]->s)+ch[1]->h     对于一个询问每次二分长度,提取区间后比较

bzoj 1014: [JSOI2008]火星人prefix hash &amp;&amp; splay

1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3154  Solved: 948[Submit][Status] Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人

BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )

用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 100009; const int P = 1000173169; ull K[maxn]; int N; char S[maxn]; struct Node { Node *ch[2], *p; int s, v; ull h; inline void

[BZOJ 1014][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(

BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分

题目大意:给定一个字符串,提供下列操作: 1.查询从x开始的后缀和从y开始的后缀的最长公共前缀长度 2.将x位置的字符修改为y 3.在x位置的字符后面插入字符y 看到这题一开始我先懵住了...这啥..我第一时间想到的是后缀数据结构 但是不会写 而且后缀数据结构也不支持修改操作 后来无奈找了题解才知道是Hash+二分... 太强大了 Hash+二分打爆一切啊 用Splay维护这个字符串的修改和插入操作 每个节点维护子串的Hash值 判断时二分找到最长公共前缀 不过这道题还有一些注意事项 1.此题不