其他分享
首页 > 其他分享> > P4036 [JSOI2008]火星人

P4036 [JSOI2008]火星人

作者:互联网

火星人

每次询问区间中的两个点 \(l,r\) 为起点的字符串的 LCP,支持单点修改和插入。

如果没有后面两个操作,直接 二分 + Hash 维护即可。

在有后面操作的情况下,我们需要一个支持 单点修改 和 插入 的数据结构,显然平衡树可以。

至于 Hash 值,简单 push_up 一下就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010;
const ULL P = 13331;

int n, m, root, tot;
char s[N];
ULL p[N];
struct Tree{int fa, v, sz, ch[2]; ULL hash;} tr[N];

int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
	while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
	return x*f;
}

void push_up(int x){
    int l = tr[x].ch[0], r = tr[x].ch[1];
    tr[x].sz = tr[l].sz + tr[r].sz + 1;
    tr[x].hash = tr[l].hash + p[tr[l].sz] * (ULL) tr[x].v + tr[r].hash * p[tr[l].sz + 1];
}

int findfa(int x) {return tr[tr[x].fa].ch[0] == x ? 0 : 1;}

void connect(int x, int fa, int son){
    tr[x].fa = fa;
    tr[fa].ch[son] = x;
}

int build(int l, int r){
    if(l > r) return 0;
    int mid = (l + r) >> 1;
    connect(build(l, mid - 1), mid, 0);
    connect(build(mid + 1, r), mid, 1);
    push_up(mid);
    return mid;
}

void rotate(int x){
    int Y = tr[x].fa, R = tr[Y].fa;
    if(Y == root)
        root = x;
    int Yson = findfa(x), Rson = findfa(Y);
    int B = tr[x].ch[Yson ^ 1];
    connect(B, Y, Yson);
    connect(Y, x, Yson ^ 1);
    connect(x, R, Rson);
    push_up(Y), push_up(x);
}

void splay(int x, int to){
    while(tr[x].fa != to){
        int y = tr[x].fa;
        if(tr[y].fa == to)
            rotate(x);
        else if(findfa(x) == findfa(y))
            rotate(y), rotate(x);
        else
            rotate(x), rotate(x);
    }
}

int find(int x){
    int now = root;
    while(true){
        if(x == tr[tr[now].ch[0]].sz + 1) return now;
        if(x < tr[tr[now].ch[0]].sz + 1) now = tr[now].ch[0];
        else x -= tr[tr[now].ch[0]].sz + 1, now = tr[now].ch[1];
    }
}

ULL Get_Hash(int l, int r){
    int x = find(l), y = find(r + 2);
    splay(x, 0), splay(y, x);
    return tr[tr[y].ch[0]].hash;
}

int main(){
    p[0] = 1;
    for(int i = 1; i <= 100000; i ++) p[i] = p[i - 1] * P;
    scanf("%s", s + 1); n = strlen(s + 1);
    for(int i = 2; i <= n + 1; i ++)
        tr[i].v = tr[i].hash = s[i - 1] - 'a' + 1;
    root = build(1, n + 2);
    tot = n + 2;
    m = read(); char opt[3], c[3];
    while(m --){
        scanf("%s", opt);
        if(opt[0] == 'Q'){
            int x = read(), y = read();
            if(x > y) swap(x, y);
            int l = 0, r = tot - y - 1;
            while(l < r){
                int mid = (l + r + 1) >> 1;
                if(Get_Hash(x, x + mid - 1) == Get_Hash(y, y + mid - 1))
                    l = mid;
                else
                    r = mid - 1;
            }
            printf("%d\n", l);
        }
        else if(opt[0] == 'R'){
            int x = read(); scanf("%s", c);
            splay(find(x + 1), 0);
            tr[root].v = c[0] - 'a' + 1;
            push_up(root);
        }
        else{
            int x = read(); scanf("%s", c);
            int u = find(x + 1), v = find(x + 2);
            splay(u, 0), splay(v, u);
            connect(++ tot, tr[root].ch[1], 0);
            tr[tot].hash = tr[tot].v = c[0] - 'a' + 1;
            tr[tot].sz = 1;
            splay(tot, 0);
        }
    }
    return 0;
}

标签:火星人,P4036,int,JSOI2008,tr,mid,splay,ch,now
来源: https://www.cnblogs.com/lpf-666/p/14598881.html