• 题面描述

    • 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:\(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\)函数的值。
  • 输入格式
    • 第一行给出初始的字符串。第二行是一个非负整数\(M\),表示操作的个数。接下来的\(M\)行,每行描述一个操作。操作有\(3\)种,如下所示

      • 询问

        • 语法:\(Q\ x\ y\),\(x,y\)均为正整数。
        • 功能:计算\(LCQ(x,y)\)限制:\(1<=x,y<=当前字符串长度\)。
      • 修改
        • 语法:\(R\ x\ d\),\(x\)是正整数,\(d\)是字符。
        • 功能:将字符串中第\(x\)个数修改为字符\(d\)。限制:\(x\)不超过当前字符串长度。
      • 插入:
        • 语法:\(I\ x\ d\),\(x\)是非负整数,\(d\)是字符。
        • 功能:在字符串第\(x\)个字符之后插入字符\(d\),如果\(x=0\),则在字符串开头插入。
        • 限制:\(x\)不超过当前字符串长度
  • 输出格式
    • 对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。
  • 题解
    • 比较水的题,码量巨大,还卡常(bzoj),我最后是开了手动O3才过的.....
    • 对于没有 修改 和 插入 操作的题目,一般主流有两种做法
      • 建出给定串的 后缀数组 或 后缀自动机,求解
      • 用字符串\(hash\),通过二分公共长度\(ans\),求解
    • 但因为题目中出现 修改 和 插入 操作,而 后缀数组 和 后缀自动机 都是静态的,因此无法维护动态插入、修改
    • 因此我们可以用的就只剩下字符串 \(hash\)了,那么问题相当于转化为动态维护 \(hash\)序列
      • 在中间某一位 \(pos\)后插入一个数

        • 这里我当时写的时候不小心把\(ins(pos)\)写成在\(pos\)前加一个数,因此之后的 插入操作 被我写成 \(ins(pos+1)\) 在\(pos+1\)前加一个数
      • 修改其中一个数
    • 这些操作可以完全被\(Splay\)胜任
  • 注意
    • 初始化\(p[]\)一定要算到\(p[10^5+5*10^4]\)上,不然之后插入字符的时候就会爆炸
    • 注意常数优化
  • 备注
    • 我在代码里附了两种算\(hash\)的方法

      • 用\(splay\)维护前缀\(hash\),在用普通\(hash\)的方法计算\(hash\)值
      • 直接用\(splay\)维护这段子串的\(hash\)值
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define ri register
#define il inline
const int inf=1e9;
const int MAXN=1e5+5e4+5;
const int mod=9875321;
int n,m,M,rt;
struct tnode{
int dat,val,fa,sz;
int ch[3];
} t[MAXN];
int p[MAXN];
char s[MAXN];
il int newnode(int val,int fa,int cl,int cr){
t[++M]=(tnode){val,val,fa,1};
t[M].ch[0]=cl; t[M].ch[1]=cr;
return M;
}
il void update(int u){
if (!u) return;
t[0].dat=t[0].sz=0;
int cl=t[u].ch[0],cr=t[u].ch[1];
int szl=t[cl].sz,szr=t[cr].sz;
t[u].sz=szl+szr+1;
t[u].dat=((ll)t[cl].dat*p[szr+1]%mod+(ll)p[szr]*t[u].val%mod+t[cr].dat)%mod;
}
il void rotate(int u){
int f1=t[u].fa;
int f2=t[f1].fa;
int dir1=t[f1].ch[1]==u;
int dir2=t[f2].ch[1]==f1;
int sn=t[u].ch[dir1^1];
t[sn].fa=f1; t[f1].ch[dir1]=sn;
t[f1].fa=u; t[u].ch[dir1^1]=f1;
t[u].fa=f2; t[f2].ch[dir2]=u;
update(f1); update(u);
}
il void splay(int u,int go){
if (u==go) return;
while (t[u].fa!=go){
int f1=t[u].fa;
int f2=t[f1].fa;
int dir1=t[f1].ch[1]==u;
int dir2=t[f2].ch[1]==f1;
if (f2==go){
rotate(u);
break;
}
if (dir1==dir2) rotate(f1);
else rotate(u);
rotate(u);
}
if (go==0) rt=u;
}
int num(int u,int rk){
int cl=t[u].ch[0],cr=t[u].ch[1];
int szl=t[cl].sz,szr=t[cr].sz;
if (cl==0&&cr==0) return u;
if (rk<=szl) return num(cl,rk);
else if (rk>szl+1) return num(cr,rk-szl-1);
else return u;
}
il void ins(int key,char c){
int cdat=c-'a'+1;
if (abs(key)>=inf) cdat=0;
if (rt==0){
rt=newnode(cdat,0,0,0);
return;
}
splay(num(rt,key+1),0);
int u=rt;
int cl=t[u].ch[0];
rt=newnode(cdat,0,cl,u);
t[u].fa=rt; t[cl].fa=rt;
t[u].ch[0]=0;
update(u); update(rt);
}
/*int qry(int key){
splay(num(rt,key+2),0);
// cout<<__func__<<key<<" "<<(char)(t[rt].val+'a'-1)<<" "<<t[t[rt].ch[0]].dat<<endl;
return t[t[rt].ch[0]].dat%mod;
}
bool check(int x,int y,int mid){
int xr=x+mid-1,yr=y+mid-1;
cout<<x<<" "<<xr<<" "<<y<<" "<<yr<<endl;
if (xr>n||yr>n) return 0;
// cout<<qry(xr)<<" "<<qry(x-1)<<endl;
int ansx=(ll)((qry(xr)-(ll)qry(x-1)*p[mid]%mod)%mod+mod)%mod;
int ansy=(ll)((qry(yr)-(ll)qry(y-1)*p[mid]%mod)%mod+mod)%mod;
cout<<ansx<<" "<<ansy<<endl;
return ansx==ansy;
}*/
il int qry(int l,int r){
splay(num(rt,l),0);
splay(num(rt,r+2),rt);
return t[t[t[rt].ch[1]].ch[0]].dat%mod;
}
il bool check(int x,int y,int mid){
int xr=x+mid-1,yr=y+mid-1;
if (xr>n||yr>n) return 0;
return qry(x,xr)==qry(y,yr);
}
il void solve(int x,int y){
if (x==y){
printf("%d\n",n-x+1);
return;
}
int l=0,r=max(n-x+1,n-y+1)+1,mid;
// cout<<__func__<<" "<<l<<" "<<r<<endl;
while (l+1<r){
mid=(l+r)>>1;
if (check(x,y,mid)) l=mid;
else r=mid;
}
printf("%d\n",l);
}
void prt(int u){
int cl=t[u].ch[0],cr=t[u].ch[1];
printf("id:%d c:%d dat:%d fa:%d cl:%d cr:%d\n",u,t[u].val,t[u].dat,t[u].fa,cl,cr);
if (cl) prt(cl);
// printf("%c",(char)t[u].val+'a'-1);
if (cr) prt(cr);
}
int main(){
// freopen("1014.in","r",stdin);
// freopen("1014.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1);
p[0]=1;
for (ri int i=1;i<=105000;i++) p[i]=(ll)p[i-1]*27%mod;
ins(inf,'a'); ins(-inf,'a');
for (ri int i=1;i<=n;i++) ins(i,s[i]);
// prt(rt);cout<<endl;
scanf("%d",&m);
for (ri int i=1;i<=m;i++){
char c=getchar(); while (c!='Q'&&c!='R'&&c!='I') c=getchar();
int x; scanf("%d",&x);
if (c=='Q'){
int y; scanf("%d",&y);
solve(x,y);
}
if (c=='R'){
char y=getchar(); while (y<'a'||y>'z') y=getchar();
splay(num(rt,x+1),0);
t[rt].val=y-'a'+1;
update(rt);
}
if (c=='I'){
char y=getchar(); while (y<'a'||y>'z') y=getchar();
ins(x+1,y);
n++;
}
// prt(rt); cout<<endl;
}
fclose(stdin); fclose(stdout);
return 0;
}

天助自助者

随机推荐

  1. Ubuntu14.04 下安装Samba服务

    1.更改linux镜像源: # vim /etc/apt/sources.list deb http://mirrors.163.com/ubuntu/ trusty main restricted ...

  2. java 访问HTTPS rest服务

    import java.io.*;import java.net.*;import java.security.cert.CertificateException;import java.securi ...

  3. 设计模式6---代理模式(Proxy Pattern)

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 1.  静态代理 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象都实现相同的接口或者是继承相同父类. 接口:IUser ...

  4. mysql多字段唯一索引

    项目中需要用到联合唯一索引: 例如:有以下需求:每个人每一天只有可能产生一条记录:处了程序约定之外,数据库本身也可以设定: 例如:user表中有userID,userName两个字段,如果不希望有2条 ...

  5. MySQL如何查看连接数和状态

    查看连接数 命令:show processlist 如果要是root账号,能够看见当前所有用户的连接.如果是普通账号,只能看到自己占用的连接数.   show processlist只能是列出前100 ...

  6. Android-自定义RadioButton

    1.控件RadioButton需要用RadioGroup包裹起来,才能使用2.RadioButton必须设置ID才能实现单选功能3.RadioGroup有方向(垂直方向 和 水平方向)默认是垂直方向 ...

  7. Luckily general gradient for spherical harmonics is defined

    http://web4.cs.ucl.ac.uk/staff/j.kautz/publications/gradientSH_RS04.pdf

  8. Java中获取运行代码的类名、方法名

    以下是案例,已运行通过 package com.hdys; /* * 1.获取当前运行代码的类名,方法名,主要是通过java.lang.StackTraceElement类 * * 2. * [1]获 ...

  9. Binder学习笔记(一)

    网上看了很多关于binder的文章,但我还是想把自己的心路历程记录下来,有些是跟着别人的脚步领略险峻风景,有些则是自己只身探入代码深处打捞出的收获.我不确定是否全部融会贯通,更担心一两个月后会完全不记 ...

  10. Python进程间通信之共享内存

    前一篇博客说了怎样通过命名管道实现进程间通信,但是要在windows是使用命名管道,需要使用python调研windows api,太麻烦,于是想到是不是可以通过共享内存的方式来实现.查了一下,Pyt ...