[BZOJ1014][JSOI2008]火星人prefix

来源:互联网 发布:怎样投诉淘宝客服 编辑:程序博客网 时间:2024/04/28 02:00

[JSOI2008]火星人prefix

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个数据,没有插入操作。
Source
JSOI

Solution
-Wall -Shadow -Extra

Code

#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned int UI;#define rep(i, l, r) for (int i = (l); i <= (r); i++)#define per(i, r, l) for (int i = (r); i >= (l); i--)#define REP(i, n) for (int i = 0; i < (n); i++)#define PER(i, n) for (int i = (n)-1; i >= 0; i--)#define stack _stackconst int N = 111111;const int INF = ~0U>>2;const UI SEED = 131;template<typename T> inline void read(T &x){    x = 0; T f = 1; char ch = getchar();    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}    x *= f;}template<typename T> inline void write(T &x){    static T a[20]; int ptr = 0;    if (!x) {puts("0"); return;}    if (x < 0){putchar('-'); x = -x;}    while (x) {a[ptr++] = x % 10; x /= 10;}    per(i, ptr-1, 0) putchar('0' + a[i]);    putchar('\n');}char str[N];UI P[N];struct node{    node *ch[2], *p; UI key; int sz, val;    bool d(){return this == p->ch[1];}    void sc(node *_c, int _d) {ch[_d] = _c; _c->p = this;}}*Null, *root;inline void push_up(node *t){    t->sz = t->ch[0]->sz + t->ch[1]->sz + 1;    UI ret = t->ch[0]->key; ret = ret * SEED + t->val;    ret *= P[t->ch[1]->sz]; ret += t->ch[1]->key;    t->key = ret;}node mem[N];node *stack[N]; int top;inline void init_memory() {REP(i, N) stack[i] = mem + i; top = N;}inline node *new_node() {return stack[--top];}inline node *new_node(int v){    node *ret = new_node();    ret->val = ret->key = v; ret->sz = 0;    ret->ch[0] = ret->ch[1] = ret->p = Null;    return ret;}inline void init_null(){     Null = new_node(0);    Null->sz = Null->key = Null->val = 0;    Null->p = Null->ch[0] = Null->ch[1] = Null;}inline void rot(node *t){    node *p = t->p; int d = t->d();    p->sc(t->ch[!d], d);    if (p-p==Null) t->p == Null; else p->p->sc(t, p->d());    t->sc(p, !d); push_up(p); push_up(t);    if (p == root) root = t;}inline void splay(node *t, node *fa){    for(; t->p != fa;){        if (t->p->p == fa) rot(t);        else t->d() == t->p->d()?(rot(t->p), rot(t)):(rot(t), rot(t));    }    push_up(t);}inline node *find(int k){    for (node *t = root; ;){        int cnt = t->ch[0]->sz;        if (cnt == k) return t;        t = t->ch[k > cnt];        if (k > cnt) k -= cnt+1;     }}node *&getseq(int l, int r){    node *L = find(l); splay(L, Null);    node *R = find(r); splay(R, root);    return root->ch[1]->ch[0];}inline void Insert(int v, int pos){    node *t = new_node(v);    getseq(pos, pos + 1);    root->ch[1]->sc(t, 0);    splay(t, Null);}inline void Replace(int v, int pos){    node *t = getseq(pos-1, pos+1); t->val = t->key = v;    splay(t, Null); }inline void build(){    init_memory(); init_null(); root = new_node(0);     node *end = new_node(0); root->sc(end, 1);    splay(end, Null);}inline UI Cal(int l, int r){ node *t = getseq(l-1, r+1); return t->key; }inline void Query(int l, int r){    int ret = 0; int n = root->sz-2;    for(int i = (1<<18); i > 0; i >>= 1){        if(l+i-1<=n && r+i-1<=n && Cal(l, l+i-1) == Cal(r, r+i-1)){            ret += i; l += i; r += i;        }    }    write(ret);}int main(){    scanf("%s", str); int n = strlen(str);    P[0] = 1; rep(i, 1, N) P[i] = P[i-1] * SEED;     build(); REP(i, n) Insert(str[i], i);    int m; read(m);    while (m--){        char opt[20]; int pos, v; char ch; scanf("%s", opt);        switch (opt[0]){            case 'I': read(pos); ch = getchar(); Insert(ch, pos); break;            case 'Q': read(pos); read(v); Query(pos, v); break;            case 'R': read(pos); ch = getchar(); Replace(ch, pos); break;        }    }    return 0;   }
0 0