poj 2758 && BZOJ 2258 Checking the Text 文本校对

Description

 

为了给Wind买生日礼物,Jiajia不得不找了一份检查文本的工作。这份工作很无聊:给你一段文本 
要求比对从文本中某两个位置开始能匹配的最大长度是多少。但比无聊更糟糕的是,Jiajia的经理 
还可能往文本里面插入一些字符。 
Jiajia想用一个程序来解决这些繁琐的工作。这个程序的速度要足够快,因为Wind的生日就快要到了 
Jiajia必须赚到足够多的钱,也就是处理足够多的文本。

Input

输入文件第一行是原始文本。 
输入文件第二行是操作数n。此后n行,每行描述一条命令,命令有两种形式: 
I ch p:表示将一个字符ch插入到当前文本的第p个字符之前,如果p大于当前文本长度则表示插入到当前文本末尾; 
Q i j:表示询问当前文本从原始文本的第i个和第j个字符现在所在的位置开始能匹配的字符是多少。 
你可以认为文本初始长度不超过50000,I命令最多200条,Q命令最多20000条。

Output

对于每条Q命令输出一行,为最长匹配长度。

Sample Input

abaab
5
Q 1 2
Q 1 3
I a 2
Q 1 2
Q 1 3

Sample Output

0
1
0
3

直接hash暴力重构==1196 ms(bzoj)

treap维护hash==5512 ms(bzoj)

spaly维护hash==TLE

gg……

感谢居神贡献权限号

#include<cstdio>
#include<algorithm>
#include<cstring>
#define MN 100001
using namespace std;
int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<‘0‘||read_ca>‘9‘) read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
unsigned long long hash[MN],mi[MN];
char c[MN],p[2];
int n,m,ne[MN],pos,len,x,y;
inline void build(int x){
    for (int i=x;i<=len;i++) hash[i]=hash[i-1]*131+c[i];
}
inline int query(int x,int y){
    if (x>y) swap(x,y);
    int l=0,r=len-y+1,mid;
    while (l<r){mid=(l+r+1)>>1;if (hash[x+mid-1]-hash[x-1]*mi[mid]==hash[y+mid-1]-hash[y-1]*mi[mid]) l=mid;else r=mid-1;}
    return l;
}
int main(){
    scanf("%s",c+1);
    n=read();
    m=len=strlen(c+1);
    mi[0]=1;
    for (int i=1;i<=m+200;i++) mi[i]=mi[i-1]*131;
    for (int i=1;i<=len;i++) ne[i]=i;
    build(1);
    for (int i=1;i<=n;i++){
        scanf("%s",p);
        if (p[0]==‘I‘){
            scanf("%s",p);pos=read();
            if (pos>len) pos=len+1;
            for (int i=len;i>=pos;i--) c[i+1]=c[i];
            c[pos]=p[0];len++;
            build(pos);
            for (int i=m;i;i--) if (ne[i]>=pos) ne[i]++;else break;
        }else{
            x=read();y=read();
            printf("%d\n",query(ne[x],ne[y]));
        }
    }
}

大暴力 2856 kb 1196 ms 1350 B

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define MN 100001
using namespace std;
int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<‘0‘||read_ca>‘9‘) read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
unsigned long long mi[MN];
char c[MN],p[2];
int n,m,ne[MN],pos,len,x,y;
struct tree{
    int l,r,s,f,fa;
    unsigned long long h,c;
    tree(){
        l=r=s=h=c=0;
    }
};
struct s_tree{
    int root,size;
    tree t[100001];
    s_tree(){
        root=size=0;
    }
    inline void up(int x){
        t[x].h=(t[t[x].l].h*131+t[x].c)*mi[t[t[x].r].s]+t[t[x].r].h;
    }
    inline void rir(int &x){
        int k=t[x].r;
        t[x].r=t[k].l;
        t[k].l=x;
        t[t[x].r].fa=x;
        t[k].fa=t[x].fa;
        t[x].fa=k;
        t[k].s=t[x].s;
        t[x].s=1+t[t[x].l].s+t[t[x].r].s;
        t[k].h=t[x].h;up(x);
        x=k;
    }
    inline void lir(int &x){
        int k=t[x].l;
        t[x].l=t[k].r;
        t[k].r=x;
        t[t[x].l].fa=x;
        t[k].fa=t[x].fa;
        t[x].fa=k;
        t[k].s=t[x].s;
        t[x].s=1+t[t[x].l].s+t[t[x].r].s;
        t[k].h=t[x].h;up(x);
        x=k;
    }
    inline void insert(int &p,int x,int c,int f){
        if (!p){
            p=++size;
            t[p].c=c;
            t[p].h=c;
            t[p].s=1;
            t[p].f=rand();
            t[p].fa=f;
        }else{
            t[p].s++;
            if (t[t[p].l].s+1>=x){
                insert(t[p].l,x,c,p);
                if (t[t[p].l].f<t[p].f) lir(p);
            }else{
                insert(t[p].r,x-1-t[t[p].l].s,c,p);
                if (t[t[p].r].f<t[p].f) rir(p);
            }
        }
        up(p);
    }
    inline int ne(int x){
        int mmh=0;
        while (x){
            mmh+=t[t[x].l].s+1;
            while (t[x].fa&&t[t[x].fa].l==x) x=t[x].fa;
            x=t[x].fa;
        }
        return mmh;
    }
    inline unsigned long long hash(int p,int x){
        if ((!x)||(!p)) return 0;
        if (t[t[p].l].s==x-1) return t[t[p].l].h*131+t[p].c;else
        if (t[t[p].l].s>=x) return hash(t[p].l,x);else return (t[t[p].l].h*131+t[p].c)*mi[x-t[t[p].l].s-1]+hash(t[p].r,x-1-t[t[p].l].s);
    }
}t;
inline int query(int x,int y){
    x=t.ne(x);y=t.ne(y);
    if (x>y) swap(x,y);
    int l=0,r=len-y+1,mid;
    while (l<r){mid=(l+r+1)>>1;if (t.hash(t.root,x+mid-1)-t.hash(t.root,x-1)*mi[mid]==t.hash(t.root,y+mid-1)-t.hash(t.root,y-1)*mi[mid]) l=mid;else r=mid-1;}
    return l;
}
int main(){
    scanf("%s",c+1);
    n=read();
    m=len=strlen(c+1);
    mi[0]=1;
    for (int i=1;i<=1e5;i++) mi[i]=mi[i-1]*131;
    for (int i=1;i<=len;i++) ne[i]=i;
    for (int i=1;i<=len;i++) t.insert(t.root,i,c[i],0);
    for (int i=1;i<=n;i++){
        scanf("%s",p);
        if (p[0]==‘I‘){
            scanf("%s",p);pos=read();
            if (pos>len) pos=len+1;t.insert(t.root,pos,p[0],0);
            len++;
        }else{
            x=read();y=read();
            printf("%d\n",query(x,y));
        }
    }
}

treap 5604 kb 5512 ms 2929 B

暴力又短又快……有毒……

时间: 2024-10-27 06:48:23

poj 2758 && BZOJ 2258 Checking the Text 文本校对的相关文章

BZOJ 2258 pku2758 Checking the Text 文本校对 Splay+Hash

题目大意:给定一个字符串,多次插入一个字符和询问某两个后缀的LCP Splay+Hash.同1014 这逗比的询问...... #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 50500 #define BASE 151 using namespace std; typedef unsigned long long ll; stru

BZOJ 2258 pku2758 Checking the Text 文本校对 Splay+Hash+二分

题目大意:初始给出一个字符串,下面有一些操作,可以在一个地方加一个字符,询问从两个地方开始最长的匹配长度. 思路:Splay维护Hash值,询问的时候二分一下就行了.它条件给的比较恶心,注意处理的时候按照他说的做就行了. CODE: #define _CRT_SECURE_NO_DEPRECATE #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #de

POJ 2758 Checking the Text(Hash+二分答案)

[题目链接] http://poj.org/problem?id=2758 [题目大意] 给出一个字符串,支持两个操作,在任意位置插入一个字符串,或者查询两个位置往后的最长公共前缀,注意查询的时候是原串下标,插入的时候则是最近更新串的下标. [题解] 因为插入操作只有两百次,所以考虑hash重构来处理匹配问题,碰到插入就重构插入点往后的哈希表,否则二分两个位置往后的匹配长度,查hash表判断是否可行. [代码] #include <cstdio> #include <algorithm&

HDU 3062 &amp;&amp; HDU 1824 &amp;&amp; POJ 3578 &amp;&amp; BZOJ 1997 2-SAT

一条边<u,v>表示u选那么v一定被选. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int Maxm=21000; 7 const int Maxn=2010; 8 struct EDGE{int to,next;}edge[Maxm]; 9 int T,m

poj 2758 多重部分和

题意:给你一个n行4列的矩阵,从每列选择一个数字,问这四个数字加起来为0的数字组合有多少个? 思路:暴力O(n4)超时,只有把前两个数字的所有和枚举出来(O(n2)),然后排序(O(nlogn)),最后枚举最后两数的所有组合,每一个组合用二分查找已经排序好的前两个数字组合(O(n2logn)),故总的复杂度是:O(n2logn) 代码: #include <set> #include <map> #include <cmath> #include <stack&g

POJ 2417/BZOJ 3239(Discrete Logging-BSGS)[Template:数论]

Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4236   Accepted: 1948 Description Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, b

poj-2758 Checking the Text

题意: 给定一个字符串,要求维护两种操作: I:在字符串中插入一个字符: Q:询问某两个位置开始的LCP: 插入操作<=200,字符串长度<=5w,查询操作<=2w: 题解: 第一道RKhash题,插入太少让这题变成了傻题: 注意题中描述的各种恶心的下标讨论: 插入下标是当前下标,而查询是原下标: 查询就是二分答案,利用RKhash快速合并的性质搞搞: 复杂度O(mlogn+100n): 单组数据,略微卡常: 代码: #include<stdio.h> #include<

POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3f using namespace std; int points,edges,k; int head[MAX],total; int next[MAX <<

POJ2758 Checking the Text

题目链接:https://vjudge.net/problem/POJ-2758 题目大意: 先给出一串原始字符串,在此基础上执行两种操作: 1.在第 p 个字符前添加字符 ch,如果 p 比现字符串的长度 nowlen 大,则添加到现字符串的末尾.注意,这里的所有位置都是相对于变化后的字符串而言的! 2.查询第 i 个和第 j 个后缀的最长公共前缀.注意,这里的位置是相对于原始字符串而言的. 解题思路: 这道题真的可以说是最近几个月我做的最痛苦的一道题之一了.真的很煎熬. 一开始,我的思路是后