火星人prefix bzoj-1014 JSOI-2004

题目大意:给定一个字符串,支持三种操作:1.查询;两个后缀之间的$LCP$;2.单点修改;3.插入一个字符。

注释:$1\le n\le 10^5$,$1\le m\le 1.5\cdot 10^5$。


想法

第一眼就是后缀数组,但是发现有单点插入操作果断$pass$。

一个序列支持单点插入肯定最少是个平衡树。

又发现$log^2n$好像能过,我们就对序列建立非旋转$Treap$然后维护子树$hash$值。

每一次查询的时候二分,然后撕出区间暴力验证即可。

时间复杂度$O(mlog^2n)$。

Code:

#include <bits/stdc++.h>
#define N 100010
using namespace std;
typedef unsigned int ull;
const ull base = 97 ;
int root,cnt; char s[N];
ull B[1000010];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
char buf[100000],*p1,*p2;
inline int rd()
{
register int x=0;register char c=nc();
while(c<'0'||c>'9')c=nc();
while(c>='0'&&c<='9')x=((x+(x<<2))<<1)+(c^48),c=nc();
return x;
}
struct Node
{
int ls,rs,size,key;
ull sum,val;
}a[N<<1];
struct par {int x,y;};
inline void pushup(int x)
{
int ls=a[x].ls,rs=a[x].rs;
a[x].sum=a[x].val; a[x].size=1;
if(ls) a[x].sum-=a[x].val,a[x].sum+=a[ls].sum+a[x].val*B[a[ls].size],a[x].size+=a[ls].size;
if(rs) a[x].sum+=a[rs].sum*B[a[ls].size+1],a[x].size+=a[rs].size;
}
int merge(int x,int y)
{
if(!x||!y) return x|y;
if(a[x].key>a[y].key)
{
a[x].rs=merge(a[x].rs,y); pushup(x);
return x;
}
else
{
a[y].ls=merge(x,a[y].ls); pushup(y);
return y;
}
}
par split(int x,int k)
{
if(!k) return (par){0,x};
int ls=a[x].ls,rs=a[x].rs;
if(k==a[ls].size)
{
a[x].ls=0; pushup(x);
return (par){ls,x};
}
else if(k==a[ls].size+1)
{
a[x].rs=0; pushup(x);
return (par){x,rs};
}
else if(k<a[ls].size)
{
par t=split(ls,k);
a[x].ls=t.y; pushup(x);
return (par){t.x,x};
}
else
{
par t=split(rs,k-a[ls].size-1);
a[x].rs=t.x; pushup(x);
return (par){x,t.y};
}
}
inline int newnode(ull val)
{
int x=++cnt;
a[x].ls=a[x].rs=0; a[x].size=1;
a[x].sum=a[x].val=val; a[x].key=rand()*rand();
return x;
}
void insert(int x,ull val)
{
par t=split(root,x);
root=merge(t.x,merge(newnode(val),t.y));
}
ull query(int x,int k)
{
par t1=split(root,x-1),t2=split(t1.y,k);
ull re=a[t2.x].sum;
root=merge(t1.x,merge(t2.x,t2.y));
return re;
}
void update(int x,ull y)
{
par t1=split(root,x-1),t2=split(t1.y,1);
root=merge(t1.x,merge(newnode(y),t2.y));
}
void output(int x)
{
int ls=a[x].ls,rs=a[x].rs;
if(ls) output(ls);
printf("%lld ",a[x].val);
if(rs) output(rs);
}
int build(int l,int r)
{
if(l==r) return newnode(s[l]-'a'+1);
int mid=(l+r)>>1;
return merge(build(l,mid),build(mid+1,r));
}
int main()
{
srand(20021214);
B[0]=1;
for(int i=1;i<=1000000;i++) B[i]=B[i-1]*base;
scanf("%s",s+1); int n=strlen(s+1);
root=build(1,n);
int m=rd(); while(m--)
{
char opt=nc(); while(opt!='Q'&&opt!='R'&&opt!='I')opt=nc(); int x=rd();
if(opt=='Q')
{
int y=rd();
int r=min(n-x+1,n-y+1)+1,l=0;
// printf("%d %d\n",x,y);
while(l<r)
{
int mid=(l+r)>>1;
// printf("%d %lld %lld\n",mid,query(x,mid),query(y,mid));
if(query(x,mid)==query(y,mid)) l=mid+1;
else r=mid;
}
printf("%d\n",l-1);
// printf("djhdjhfjhfgjuhdfgiodfg=%d\n",query(x,5)==query(y,5));
// r--;
// int d,p=0;
// for(d=1;d<=r&&query(x,d)==query(y,d);d<<=1) ;
// for(d>>=1;d;d>>=1) if(p+d<=r&&query(x,p+d)==query(y,p+d)) p+=d;
// // printf("djhdjhfjhfgjuhdfgiodfg=%d\n",query(x,5)==query(y,5));
// printf("%d\n",p);
}
else if(opt=='R')
{
char d=nc();while(d<'a'&&d>'z')d=nc(); ull val=d-'a'+1;
update(x,val);
}
else
{
n++;
char d=nc();while(d<'a'&&d>'z')d=nc(); ull val=d-'a'+1;
insert(x,val);
}
}
return 0;
}

小结:卧槽这题卡常,用特判+读入优化+非旋转$Treap$的$O(n)$建树才卡过去。

[bzoj1014][JSOI2008]火星人prefix_非旋转Treap_hash_二分的更多相关文章

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

    题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的s ...

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

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

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

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

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

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

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

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

  6. BZOJ1014[JSOI2008]火星人——非旋转treap+二分答案+hash

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

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

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

  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. IO流的原理和概念

    在程序中如何读写文件?不同的编程语言有不同的方式,而 JAVA 则提出了“流”的概念,通过“流”来读写文件 什么是流: 流(Stream)是指一连串的数据(字符或字节),是以先进先出的方式发送信息的通 ...

  2. vue项目中安装cnpm和node_modules

    1.安装cnpm的nodejs包管理工具,命令行: npm install -g cnpm --registry=https://registry.npm.taobao.org   2. 每个vue项 ...

  3. css3中的变换、动画和过渡

    变换:分为2d变换和3d变换,但一次只能用一个变换属性,多个的话最后一个会覆盖前面所有最终被浏览器实现,变换可以成为过渡和动画的一个待变参数(类似width,opacity等). 过渡:是动画的初始模 ...

  4. Android 使用EventBus进行Fragment和Activity通信

    本文介绍EventBus的基本使用,以及用于Fragment和Activity之间通信. github地址: https://github.com/greenrobot/EventBus 版本是 Ev ...

  5. spring 中文乱码问题

    spring 开发过程中的中文乱码问题主要分为以下几种: 1.前端传参数到后台前  就已经乱码. 这个很大原因就是前端的问题了! 2.传入后台后,乱码. 可能存在几个原因: 2.1 传入tomcat前 ...

  6. 黑马程序员----java基础:多线程

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ---- ...

  7. java web 学习笔记 - 表达式语言

    1.表达式语言简介 主要为了简化mvc中 jsp的代码量,方便进行属性的输出.还可以避免进行属性为空等的判断,表达式默认将null设置为"". 表达式语言的一个最大的好处就是,只需 ...

  8. JAVA——不简单的fianl关键字

    protected用来修饰 域,代表域的访问权限是:包权限 或者 不同包,但是是子类 : final 修饰常量只要是该常量代入的计算式,在编译时期,就会被执行计算,以减轻运行时的负担.(只对基本数据类 ...

  9. C#在sql中使用變量訪問Oracle數據庫

    1.首先創建一個測試數據表 CREATE TABLE people ( SNO BYTE), SNAME BYTE), SSEX BYTE), SAGE number, SDEPT BYTE), BT ...

  10. 反射(hasattr,getattr,delattr,setattr)

    反射(hasattr,getattr,setattr,delattr) 反射在类中的使用 反射就是通过字符串来操作类或者对象的属性 反射本质就是在使用内置函数,其中反射有四个内置函数: hasattr ...