Processing math: 33%

【bzoj1014】 JSOI2008—火星人prefix

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 (题目链接)

题意

  给出一个字符串,要求维护这些操作:询问后缀x与后缀y的LCQ(最长公共前缀),在第k个字符后插入一个字符,将第k个字符改成另一个字符。

Solution

  对于修改与插入操作,我们用splay维护。考虑怎么求解LCQ。

  我们可以将字符串hash,然后平衡树上每一个节点的hash值就代表的该区间的hash值,毫无疑问,这是可以向上更新的。于是问题就解决了。

细节

  注意splay中update的顺序。hash的进制要取好,不能比一位上的数范围小。hash值相乘的时候记得开long long。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define MOD 9875321
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=150010;
int tr[maxn][2],fa[maxn],id[maxn],size[maxn];
int v[maxn],h[maxn],bin[maxn];
int n,rt,sz,q;
char s[maxn];
 
void update(int k) {
    int l=tr[k][0],r=tr[k][1];
    size[k]=size[l]+size[r]+1;
    h[k]=h[l]+(LL)v[k]*bin[size[l]]%MOD+(LL)bin[size[l]+1]*h[r]%MOD;
    h[k]%=MOD;
}
void rotate(int x,int &k) {
    int y=fa[x],z=fa[y],l,r;
    l=tr[y][1]==x;r=l^1;
    if (y==k) k=x;
    else tr[z][tr[z][1]==y]=x;
    fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
    tr[y][l]=tr[x][r];tr[x][r]=y;
    update(y);update(x);
}
void splay(int x,int &k) {
    while (x!=k) {
        int y=fa[x],z=fa[y];
        if (y!=k) {
            if ((tr[z][0]==y) ^ (tr[y][0]==x)) rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
}
int find(int k,int x) {
    int l=tr[k][0],r=tr[k][1];
    if (size[l]+1==x) return k;
    else if (size[l]>=x) return find(l,x);
    else return find(r,x-size[l]-1);
}
void insert(int k,int val) {
    int x=find(rt,k+1),y=find(rt,k+2);
    splay(x,rt);splay(y,tr[x][1]);
    int z=++sz;tr[y][0]=z;fa[z]=y;v[z]=val;
    update(z);update(y);update(x);
}
int query(int k,int val) {
    int x=find(rt,k),y=find(rt,k+val+1);
    splay(x,rt);splay(y,tr[x][1]);
    return h[tr[y][0]];
}
int solve(int x,int y) {
    int l=1,r=min(sz-x,sz-y)-1,ans=0;
    while (l<=r) {
        int mid=(l+r)>>1;
        if (query(x,mid)==query(y,mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    return ans;
}
void build(int l,int r,int f) {
    if (l>r) return;
    int mid=(l+r)>>1,now=id[mid],last=id[f];
    if (l==r) {
        v[now]=h[now]=s[mid]-'a'+1;
        fa[now]=last;size[now]=1;
        tr[last][mid>=f]=now;
        return;
    }
    build(l,mid-1,mid);build(mid+1,r,mid);
    v[now]=s[mid]-'a'+1;fa[now]=last;update(now);
    tr[last][mid>=f]=now;
}
int main() {
    scanf("%s",s+2);
    n=strlen(s+2);
    bin[0]=1;for (int i=1;i<maxn;i++) bin[i]=bin[i-1]*31%MOD;
    for (int i=1;i<=n+2;i++) id[i]=i;
    build(1,n+2,0);rt=(n+3)>>1;sz=n+2;
    scanf("%d",&q);
    while (q--) {
        int x,y;char ch[10];
        scanf("%s",ch);
        scanf("%d",&x);
        if (ch[0]=='Q') scanf("%d",&y),printf("%d\n",solve(x,y));
        if (ch[0]=='R') {
            scanf("%s",ch);
            x=find(rt,x+1);splay(x,rt);
            v[rt]=ch[0]-'a'+1;update(rt);
        }
        if (ch[0]=='I') scanf("%s",ch),insert(x,ch[0]-'a'+1);
    }
    return 0;
}

  

posted @   MashiroSky  阅读(433)  评论(0编辑  收藏  举报
编辑推荐:
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
阅读排行:
· 一个适用于 .NET 的开源整洁架构项目模板
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手
· .NET 9.0 使用 Vulkan API 编写跨平台图形应用
· MyBatis中的 10 个宝藏技巧!
点击右上角即可分享
微信分享提示