BZOJ 1014 [JSOI2008]火星人prefix
Posted Achen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1014 [JSOI2008]火星人prefix相关的知识,希望对你有一定的参考价值。
splay维护hash值;
看到大佬们都在打数据结构,我说好的不打数据结构又自己打脸了。
为了写这个昨天还特意去打了Splay的普通平衡树,自从我学会Treap以来第一次用splayA掉普通平衡树QAQ
没有在前后加点,所以特判了在前后加字母的情况。查询就二分答案,然后转过去取hash值,判断是否相等。
一开始用了mod 1e9+7,狂T不止,到处翻别人的博客听说用unsigned long long 自然溢出很快,改后就快了一倍。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#define lc ch[x][0]
#define rc ch[x][1]
typedef unsigned long long LL;
const int maxn=300000+299;
using namespace std;
int len,root,tot,T,x,y,sz[maxn],ch[maxn][2],p[maxn];
LL v[maxn],ha[maxn],base=131,power[maxn];
char s[maxn],op[10],c[10];
inline int read() {
char ch=getchar(); int f=1,ret=0;
while(ch!=‘-‘&&(ch>‘9‘||ch<‘0‘)) ch=getchar();
if(ch==‘-‘) f=-1,ch=getchar();
for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) ret=ret*10+ch-‘0‘;
return ret*f;
}
void update(int x) {
sz[x]=sz[lc]+sz[rc]+1;
ha[x]=(ha[lc]*power[sz[rc]+1]+v[x]*(power[sz[rc]])+ha[rc]);
}
void rotate(int x) {
int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
if(z) ch[z][y==ch[z][1]]=x; p[x]=z;
ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
ch[x][r]=y; p[y]=x;
update(y); update(x);
}
void splay(int x,int FA) {
if(p[x]==FA) return;
for(;p[x]!=FA;rotate(x)) {
int y=p[x],z=p[y];
if(z!=FA) (y==ch[z][1])^(x==ch[y][1])?rotate(x):rotate(y);
}
if(!FA) root=x;
}
int build(int l,int r) {
int x=++tot;
sz[x]==1;
int mid=(l+r)>>1;
v[x]=s[mid-1];
if(mid-1>=l) lc=build(l,mid-1);
if(mid+1<=r) rc=build(mid+1,r);
if(lc) p[lc]=x;
if(rc) p[rc]=x;
update(x);
return x;
}
int kth(int k) {
int res=-1;
for(int x=root;x;) {
if(sz[lc]+1==k) return x;
if(sz[lc]+1>k) x=lc;
else k-=(sz[lc]+1),x=rc;
}
}
LL find(int l,int r) {
int ll=kth(l),rr=kth(r);
if(ll==rr) return v[ll];
splay(ll,0);
splay(rr,ll);
LL res=v[root]*power[sz[ch[ch[root][1]][0]]+1]+ha[ch[ch[root][1]][0]]*power[1]+v[ch[root][1]];
return res;
}
int ef(int x,int y) {
int res=0;
if(x>y) swap(x,y);
if(x==y) return sz[root]-y+1;
int l=0,r=sz[root]-y;
while(l<=r) {
int mid=(l+r)>>1;
if(find(x,x+mid)==find(y,y+mid)) res=mid+1,l=mid+1;
else r=mid-1;
}
return res;
}
int main()
{
scanf("%s",s);
len=strlen(s);
power[0]=1;
for(int i=1;i<=maxn-290;i++) power[i]=power[i-1]*base;
root=build(1,len);
T=read();
while(T--) {
scanf("%s",op);
if(op[0]==‘Q‘) {
scanf("%d%d",&x,&y);
printf("%d\n",ef(x,y));
}
else if(op[0]==‘R‘) {
scanf("%d%s",&x,c);
int ll=kth(x);
splay(ll,0);
v[root]=c[0];
update(root);
}
else {
scanf("%d%s",&x,c);
if(x==0) {
int ll=kth(1);
splay(ll,0);
ch[root][0]=++tot;
sz[tot]=1; p[tot]=root;
v[tot]=ha[tot]=c[0];
update(root);
}
else {
int ll=kth(x);
splay(ll,0);
if(x==sz[root]) {
ch[root][1]=++tot;
sz[tot]=1; p[tot]=root;
v[tot]=ha[tot]=c[0];
update(root);
}
else {
int ll=kth(x);
splay(ll,0);
int rr=kth(x+1);
splay(rr,ll);
ch[rr][0]=++tot;
sz[tot]=1; p[tot]=rr;
v[tot]=ha[tot]=c[0];
update(rr);
update(root);
}
}
}
}
return 0;
}
以上是关于BZOJ 1014 [JSOI2008]火星人prefix的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)