1014: [JSOI2008]火星人prefix

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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 现在,火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。

Input

第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操作有3种,如下所示: 1、 询问。语法:Q x y,x, y均为正整数。功能:计算LCQ(x, y) 限制:1 <= x, y <= 当前字符串长度。 2、 修改。语法:R x d,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字符串长度。 3、 插入:语法:I x d,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x = 0,则在字符串开头插入。限制:x不超过当前字符串长度。

Output

对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。

Sample Input

madamimadam
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11

Sample Output

5
1
0
2
1

HINT

数据规模:

对于100%的数据,满足:

1、 所有字符串自始至终都只有小写字母构成。

2、 M <= 150,000

3、 字符串长度L自始至终都满足L <= 100,000

4、 询问操作的个数不超过10,000个。

对于第1,2个数据,字符串长度自始至终都不超过1,000

对于第3,4,5个数据,没有插入操作。

  这道题在知道用hash做之后,还是不会,其实这道题用hash转换为另一道题,给定一个序列,支持插入,改变值,询问区间hash值,这样就可以用splay维护。

  一个需要注意的东西,字符串hash+自然溢出时,如果进制用的是偶数(26)是会挂掉滴。

  splay写的还是太慢了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXT 400000
#define MAXN 210000
unsigned int mi[MAXN];
struct Splay_tree
{
int ch[MAXT][],pnt[MAXT],val[MAXT],siz[MAXT];
unsigned int hs[MAXT];
int root;
int topt;
void update(int now)
{
siz[now]=siz[ch[now][]]+siz[ch[now][]]+;
hs[now]=hs[ch[now][]] + val[now]*mi[siz[ch[now][]]] + hs[ch[now][]]*(mi[siz[ch[now][]]+]);
}
void rotate(int now)
{
int p=pnt[now],anc=pnt[p];
int dir=(ch[p][]==now);
if (anc)ch[anc][ch[anc][]==p]=now;
pnt[now]=anc;
pnt[ch[now][dir]]=p;
ch[p][-dir]=ch[now][dir];
pnt[p]=now;
ch[now][dir]=p;
update(p);
update(now);
}
void splay(int now,int tp=)
{
while (now!=tp && pnt[now]!=tp)
{
int p=pnt[now],anc=pnt[p];
if (anc==tp)
{
rotate(now);
}else
{
if((ch[anc][]==p) == (ch[p][]==now))
rotate(p),rotate(now);
else
rotate(now),rotate(now);
}
}
if (!tp)
root=now;
return ;
}
int get_kth(int now,int rk)
{
if (!now)return -;
if (siz[ch[now][]]+==rk)
return now;
else if (siz[ch[now][]]+<rk)
return get_kth(ch[now][],rk-siz[ch[now][]]-);
else return get_kth(ch[now][],rk);
}
void insert(int pos,int v)
{
if (!root)
{
root=++topt;
val[topt]=v;
pnt[topt]=;
update(topt);
return ;
}
if (!pos)
{
splay(get_kth(root,),);
ch[root][]=++topt;
ch[topt][]=ch[topt][]=;
val[topt]=v;
pnt[topt]=root;
update(topt);
update(root);
return ;
}
splay(get_kth(root,pos));
if (pos+<=siz[root])
splay(get_kth(root,pos+),root);
//scan(root);
if (!ch[root][])
{
ch[root][]=++topt;
pnt[topt]=root;
}else
{
ch[ch[root][]][]=++topt;
pnt[topt]=ch[root][];
}
ch[topt][]=ch[topt][]=;
val[topt]=v;
update(topt);
if (ch[root][]!=topt)
update(ch[root][]);
update(root);
}
void change_val(int pos,int v)
{
splay(get_kth(root,pos));
val[root]=v;
update(root);
}
unsigned int query(int l,int r)
{
if (l== && r==siz[root])
{
// scan(root);
return hs[root];
}else if (l==)
{
splay(get_kth(root,r+));
// scan(ch[root][0]);printf("\n");
return hs[ch[root][]];
}else if (r==siz[root])
{
splay(get_kth(root,l-));
// scan(ch[root][1]);printf("\n");
return hs[ch[root][]];
}else
{
splay(get_kth(root,r+));
splay(get_kth(root,l-),root);
// scan(ch[ch[root][0]][1]);printf("\n");
return hs[ch[ch[root][]][]];
}
}
void scan(int now)
{
if (!now)
return ;
if (ch[now][] && pnt[ch[now][]]!=now)throw ;
if (ch[now][] && pnt[ch[now][]]!=now)throw ;
if (siz[now]!=siz[ch[now][]]+siz[ch[now][]]+)throw ;
if (hs[now]!=hs[ch[now][]]+val[now]*mi[siz[ch[now][]]]+hs[ch[now][]]*(mi[siz[ch[now][]]+]))throw ;
scan(ch[now][]);
printf("%d[%c] ",val[now],val[now]+'a');
scan(ch[now][]);
}
}pp;
char str[MAXN];
int main()
{
freopen("input.txt","r",stdin);
mi[]=;
int i;
for (i=;i<MAXN;i++)
mi[i]=mi[i-]*;
scanf("%s",str);
int n=strlen(str);
while (!islower(str[n-]))
n--;
for (i=;i<n;i++)
{
pp.insert(i,str[i]-'a');
}
int m;
scanf("%d\n",&m);
char opt;
char ch;
int x,y;
for (i=;i<m;i++)
{
scanf("%c",&opt);
if (opt=='Q')
{
scanf("%d%d\n",&x,&y);
if (x>y)swap(x,y);
int l=,r=n-y+,mid;
while(l+<r)
{
mid=(l+r)>>;
if (pp.query(x,x+mid-)==pp.query(y,y+mid-))
l=mid;
else
r=mid;
}
printf("%d\n",l);
}else if (opt=='R')
{
scanf("%d %c\n",&x,&ch);
pp.change_val(x,ch-'a');
}else if (opt=='I')
{
scanf("%d %c\n",&x,&ch);
pp.insert(x,ch-'a');
n++;
}
}
}

bzoj 1014: [JSOI2008]火星人prefix hash && splay的更多相关文章

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

    题目链接:BZOJ - 1014 题目分析 求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等. 这里有修改 ...

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

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1014 [题意] 给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP ...

  3. BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6243  Solved: 2007[Submit] ...

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

    用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ...

  5. BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 8112  Solved: 2569[Submit] ...

  6. BZOJ 1014: [JSOI2008]火星人prefix Splay+二分

    1014: [JSOI2008]火星人prefix 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1014 Description 火星人 ...

  7. 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4164  Solved: 1277[Submit] ...

  8. 【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014 题意:支持插入一个字符.修改一个字符,查询lcp.(总长度<=100000, 操作< ...

  9. BZOJ 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)

    题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度 乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾) 看题解才知道这是一道splay题,首先要对s ...

随机推荐

  1. 【MongoDB】The Access control of mongodb

    In this blog we mainly talk about the access control including limitation of ip, setting listen port ...

  2. 自定义toast功能

    http://download.csdn.net/detail/caryt/8105031

  3. oracle17 视图

    oracle的视图 介绍 视图是一个虚拟表是一个表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据.但是,视图并不在数据库中以存储的数据值集形式存在(视图不实际存在).行和列数据 ...

  4. ubuntu首次给root用户设置密码

    用过ubuntu的人都知道,刚安装好root用户是没有密码的,没有密码我们就没法用root用户登录 给root用户设置密码输入命令sudo passwd,然后系统会让你输入密码,这时输入的密码就是ro ...

  5. CentOS7安装Cobbler

    安装EPEL源 # rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 安装cobbler ...

  6. Linux netstat命令参数解释

    netstat –ntlp 显示 tcp 的监听端口 netstat –ntlp 显示 tcp udp 的监听端口 netstat –r 显示路由表 netstat –rn 显示路由表不做名称解析(较 ...

  7. 直接在存储过程里面写sql语句的话 ,会返回操作的结果

    ALTER PROCEDURE [dbo].[sp_updateStuStateYRCode] @StuId varchar(100)ASBEGIN update StuState set KM1YR ...

  8. php快速定位多维数组的深度

    原文地址:php快速定位多维数组的深度作者:陌上花开 自定义一个函数: function array_depth($array)  { $max_depth = 1; foreach ($array ...

  9. php面向对象设计模式

    为什么学习设计模式: 1,更深入的了解面向对象的思想 2,有利于开发出扩展性强的东西 什么是设计模式:经常出现的典型场景的典型解决方案,就是设计模式.举个例子生活中的设计模式:比如泡妞思路,象棋招数等 ...

  10. JAVA 循环在一个数字前面填充0.小例子

    输入结果 00000000000567 String bala="567"; 固定长度是14位,怎么循环在bala前面填充00000000000 System.out.printl ...