Jewel Magic UVA - 11996

这是一道用splay/非旋treap做的题(这里用的是非旋treap)

1/2/3是splay/非旋treap的常规操作。对于操作4,可以用哈希法求LCP。记hash(i,L)为子串[i,i+L-1](即第i个开始的L个)的hash值。记s[i]为序列第i位(编号从1开始),n为序列长度

如果通过某种方式做到能在O(logn)时间内取出一段子串的hash值,那么二分答案(即LCP长度x),可以在O(logn)时间内判一个x是否合法(如果hash(l,x)==hash(r,x)则认为[l,l+x-1]和[r,r+x-1]是相同的,合法,否则不合法),可以做到在O(log^2n)内完成一个操作4。当然,hash判字符串是否相同正确性可能受影响,因此可以多计算一些hash,当他们都相同时才认为字符串相同,可以将错误率降到足够小。

如何维护一段子串的hash值?首先定义x为任意整数,定义$hash(i,L)=s[i+L-1]*x^{L-1}+s[i+L-2]*x^{L-2}+...+s[i+1]*x+s[i]$

(这里及之后都省略了取模)

(简单记法:左边乘的次数小)

(另一种记法:另一种求法的伪代码表示:ans=0;for(j=i+L-1;j>=i;j--)  ans=ans*x+s[j];)

可以发现:如果已知hash(i,p)和hash(i+p,q)(即已知[i,i+p-1]和[i+p,i+p+q-1]的hash值),要求hash(i,p+q)(就是这两段合起来的hash值),那么:

令j=i+p,那么$hash(i,p+q)$

$=s[j+q-1]*x^{p+q-1}+s[j+q-2]*x^{p+q-2}+...+s[j]*x^p+s[i+p-1]*x^{p-1}+...+s[i]*x^0$

所以$hash(i,p+q)=hash(j,q)*x^p+hash(i,p)=hash(i,p)+hash(i+p,q)*x^p$

这样就得到了对于平衡树某个节点,根据子节点为根的子树的hash值与自身值求以自身为根的子树的hash值的方法(先将左子树和自身合起来,再将结果与右子树合起来)

当然,由于此题有一个翻转操作,对于一个节点要维护两个hash:正向序列hash和反向序列hash。翻转操作时顺便交换一下两个的值。

附:这道题没有卡hash,单hash就能过,

附:听说操作4有O(logn)的方法?待解决

错误记录:

1.141行误用build函数(build是用的左闭右闭区间),输入了(a+1,a+n+1)。(然而不知道为什么虽然过不了udebug的数据然而把题目A掉了)

2.没注意在字符前还是字符后插入

*3.posib函数写错:没有考虑要计算hash值的串超出长度范围的情况(就是第二个"&&"之前的部分)。错了不止一次

4.可能出现的错误:如果hash不用ull自然溢出,自己取模,那么要考虑爆int、爆longlong、负数等等

 #include<cstdio>
#include<algorithm>
using namespace std;
inline int rand1()
{
static int x=;
return x=(48271LL*x+)%;
}
unsigned long long powx[];
struct Node
{
Node(){}
Node* ch[];
int r;
bool flip;
int v;
unsigned long long h,rh;
int size;
void upd()
{
if(ch[]) ch[]->pd();
if(ch[]) ch[]->pd();
size=+(ch[]?ch[]->size:)+(ch[]?ch[]->size:);
h=(ch[]?ch[]->h:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->h:)*powx[(ch[]?ch[]->size:)+];
rh=(ch[]?ch[]->rh:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->rh:)*powx[(ch[]?ch[]->size:)+];
}
void pd()
{
if(flip)
{
swap(ch[],ch[]);
swap(h,rh);
if(ch[]) (ch[]->flip)^=;
if(ch[]) (ch[]->flip)^=;
flip=;
}
}
}nodes[];
Node* root;int mem;
Node* getnode(){return nodes+(mem++);}
Node* merge(Node* a,Node* b)
{
if(a==NULL) return b;
if(b==NULL) return a;
if(a->r < b->r)
{
a->pd();a->ch[]=merge(a->ch[],b);a->upd();
return a;
}
else
{
b->pd();b->ch[]=merge(a,b->ch[]);b->upd();
return b;
}
}
typedef pair<Node*,Node*> P;
P split(Node* a,int n)
{
if(a==NULL) return P(NULL,NULL);
P y;
a->pd();int s=a->ch[] ? a->ch[]->size : ;
if(s>=n)
{
y=split(a->ch[],n);
a->ch[]=y.second;a->upd();
y.second=a;
}
else
{
y=split(a->ch[],n-s-);
a->ch[]=y.first;a->upd();
y.first=a;
}
return y;
}
inline void insert(int k,int x)
{
Node* t=getnode();
t->ch[]=t->ch[]=NULL;t->r=rand1();t->v=x;t->flip=;t->upd();
P y=split(root,k-);
root=merge(merge(y.first,t),y.second);
}
inline void erase(int k)
{
P y=split(root,k-);
P y2=split(y.second,);
root=merge(y.first,y2.second);
}
inline void reverse(int l,int r)
{
if(l>r) swap(l,r);
P y=split(root,l-);
P y2=split(y.second,r-l+);
y2.first->flip^=;
root=merge(merge(y.first,y2.first),y2.second);
}
inline int size()
{
return root ? root->size : ;
}
inline unsigned long long geth(int l,int r)
{
if(l>r) return ;
P y=split(root,l-);
P y2=split(y.second,r-l+);
unsigned long long ans=y2.first ? y2.first->h : ;
root=merge(merge(y.first,y2.first),y2.second);
return ans;
}
Node* build(int *l,int *r)
{
if(l>r) return NULL;
if(l==r)
{
Node* t=getnode();
t->ch[]=t->ch[]=NULL;t->r=rand1();t->v=*l;t->flip=;t->upd();
return t;
}
else
{
int* mid=l+(r-l)/;
return merge(build(l,mid),build(mid+,r));
}
}
int n,m,q;
int a[];
const int X=;
int l,r;
inline bool posib(int x)
{
return (l+x-<=size())&&(r+x-<=size())&&(geth(l,l+x-)==geth(r,r+x-));
}
int main()
{
register int i;
int lx,rx,k,x,mid,tmp;
powx[]=;
for(i=;i<=;i++) powx[i]=powx[i-]*X;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++) scanf("%1d",&a[i]);
root=build(a+,a+n);
while(q--)
{
scanf("%d",&tmp);
if(tmp==)
{
scanf("%d%d",&k,&x);
insert(k+,x);
}
else if(tmp==)
{
scanf("%d",&k);
erase(k);
}
else if(tmp==)
{
scanf("%d%d",&l,&r);
reverse(l,r);
}
else if(tmp==)
{
scanf("%d%d",&l,&r);
lx=;rx=size()+;
while(rx-lx>)
{
mid=(lx+rx)>>;
if(posib(mid)) lx=mid;
else rx=mid;
}
printf("%d\n",lx);
}
}
return ;
}

https://www.lydsy.com/JudgeOnline/problem.php?id=1014

https://www.luogu.org/problemnew/show/P4036

贴一下常数超大的代码

做法类似

 #pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
inline int rand1()
{
static int x=;
return x=(48271LL*x+)%;
}
unsigned long long powx[];
struct Node
{
Node(){}
Node* ch[];
int r;
int v;
unsigned long long h;
int size;
void upd()
{
size=+(ch[]?ch[]->size:)+(ch[]?ch[]->size:);
h=(ch[]?ch[]->h:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->h:)*powx[(ch[]?ch[]->size:)+];
}
}nodes[];
Node* root;int mem;
Node* getnode(){return nodes+(mem++);}
Node* merge(Node* a,Node* b)
{
if(a==NULL) return b;
if(b==NULL) return a;
if(a->r < b->r)
{
a->ch[]=merge(a->ch[],b);a->upd();
return a;
}
else
{
b->ch[]=merge(a,b->ch[]);b->upd();
return b;
}
}
typedef pair<Node*,Node*> P;
P split(Node* a,int n)
{
if(a==NULL) return P(NULL,NULL);
P y;
int s=a->ch[] ? a->ch[]->size : ;
if(s>=n)
{
y=split(a->ch[],n);
a->ch[]=y.second;a->upd();
y.second=a;
}
else
{
y=split(a->ch[],n-s-);
a->ch[]=y.first;a->upd();
y.first=a;
}
return y;
}
inline void insert(int k,int x)
{
Node* t=getnode();
t->r=rand1();t->v=x;t->upd();
P y=split(root,k-);
root=merge(merge(y.first,t),y.second);
}
inline void erase(int k)
{
P y=split(root,k-);
P y2=split(y.second,);
root=merge(y.first,y2.second);
} inline int size()
{
return root ? root->size : ;
}
inline unsigned long long geth(int l,int r)
{
if(l>r) return ;
P y=split(root,l-);
P y2=split(y.second,r-l+);
unsigned long long ans=y2.first ? y2.first->h : ;
root=merge(merge(y.first,y2.first),y2.second);
return ans;
}
Node* build(char *l,char *r)
{
if(l>r) return NULL;
if(l==r)
{
Node* t=getnode();
t->r=rand1();t->v=(int)(*l);t->upd();
return t;
}
else
{
char* mid=l+(r-l)/;
return merge(build(l,mid),build(mid+,r));
}
}
int n,m,q;
char a[];
const int X=;
int l,r;
char tmp;
inline bool posib(int x)
{
return (l+x-<=size())&&(r+x-<=size())&&(geth(l,l+x-)==geth(r,r+x-));
}
int main()
{
register int i;
int lx,rx,k,mid;
powx[]=;
for(i=;i<=;i++) powx[i]=powx[i-]*X;
scanf("%s",a+);n=strlen(a+);
root=build(a+,a+n);
scanf("%d",&q);
while(q--)
{
tmp=getchar();while(tmp<'A'||tmp>'Z') tmp=getchar();
if(tmp=='I')
{
scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar();
insert(k+,(int)tmp);
}
else if(tmp=='R')
{
scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar();
erase(k);insert(k,(int)tmp);
}
else if(tmp=='Q')
{
scanf("%d%d",&l,&r);
lx=;rx=size()+;
while(rx-lx>)
{
mid=(lx+rx)>>;
if(posib(mid)) lx=mid;
else rx=mid;
}
printf("%d\n",lx);
}
}
return ;
}

Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix的更多相关文章

  1. [BZOJ1014][JSOI2008]火星人prefix

    [BZOJ1014][JSOI2008]火星人prefix 试题描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字 ...

  2. BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*

    BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...

  3. 2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)

    [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MB Submit: 8951 Solved: 2860 Description 火星 ...

  4. bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...

  5. [BZOJ1014] [JSOI2008] 火星人prefix (splay & 二分答案)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  6. bzoj1014: [JSOI2008]火星人prefix splay+hash+二分

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  7. [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...

  8. BZOJ1014[JSOI2008]火星人prefix(splay维护hash)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  9. BZOJ1014: [JSOI2008]火星人prefix(splay 二分 hash)

    题意 题目链接 Sol 一眼splay + 二分hash,不过区间splay怎么写来着呀 试着写了两个小时发现死活不对 看了一下yyb的代码发现自己根本就不会splay.... // luogu-ju ...

随机推荐

  1. maven打包时的三方包的选择顺序

    在一个项目有多个模块引用多个版本的某个插件(或者叫三方包.jar包等)时,如何解决版本冲突问题?最终选用某个版本还是选择几个版本? maven在遇到上面的情况时,会智能处理版本冲突,最终选择一个版本, ...

  2. 【nginx】【转】Nginx核心进程模型

    一.Nginx整体架构 正常执行中的nginx会有多个进程,最基本的有master process(监控进程,也叫做主进程)和woker process(工作进程),还可能有cache相关进程.   ...

  3. webx启动流程

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTFRpYW5jaGFv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...

  4. SharePoint 2013 调查问卷的使用方法

    SharePoint 2013 调查问卷的使用方法 1,介绍调查问卷的用法. 2.图形和全部结果. 3,控制用户仅仅能看到自己答案. 1.确认有权限,假设没有管理管理权限请向管理员申请. 站点&quo ...

  5. 火狐浏览器Firefox 如何使用iMacros 自动填写网页表单

    1 我们首先访问一个想要自动填写表单的网站.我们以百度为例,右侧有登录窗口.   2 然后我们点开刚安装上的iMacros插件,一般安装之后就会自动出现在浏览器的某个地方,点击记录选项卡,再点击记录. ...

  6. 机器学习和深度学习笔记(Matlab语言实现)

    不多说,直接上干货! 这里,对于想用matlab语言来做的朋友,强烈推荐 http://www.cnblogs.com/tornadomeet/

  7. angularjs学习之六(angularjs中directive指令的一般编程事件绑定 模板使用等)

    angular js 中模板的使用.事件绑定以及指令与指令之间的交互 相应教学视频地址(需FQ):v=aG8VD0KvUw4">angularjs教学视频 <!doctype h ...

  8. jquery获取兄弟元素

    按照w3c school的指引,jquery中,要获得一个元素的兄弟,可以用 prev().next()两种方法.顾名思义,prev()获得前一个,next()获得后面一个. 问题是,如果存在前后兄弟 ...

  9. 必备java参考资源列表

    现在开始正式介绍这些参考资源. Web 站点和开发人员 Web 门户 网络无疑改变了共享资源和出版的本质(对我也是一样:您正在网络上阅读这篇文章),因此,从每位 Java 开发人员都应该关注的关键 W ...

  10. C项目案例实践(0)-语言基础

    1.C语言数据类型 所谓数据类型是按被定义变量的性质.表示形式.占据存储空间的多少.构造特点来划分的.C中数据类型可分为基本数据类型.构造数据类型.指针类型.空类型4大类,结构如图: (1)基本数据类 ...