【bzoj 3946】 无聊的游戏 - 线段树套可持久化Treap

  蜜汁卡常卡过去了。。。
  考虑用线段树维护区间的LCP,如果设 height[i]=LCP(S[i],S[i+1]) ,那么 LCP(S[l]...S[r])=min(height[l]...height[r1])
  只要能快速维护 height ,就可以快速查询。
  于是考虑如何处理修改。
  可以发现区间加前缀的时候, [l...r1] height 相当于直接加上了前缀的长度,而 height[l1] height[r] 变得不确定了,于是可以重新算这两个位置的 height 。前一半区间加的部分可以直接线段树搞搞,后一半需要知道这个串现在长什么样。
  于是考虑如何算 height[i] 。我们可以用Treap维护每个字符串的哈希值,于是区间插入的时候相当于区间的Treap前面join再上一个Treap。因此可以将Treap可持久化之后直接当线段树上的标记来推。这样每次推标记的复杂度就是 O(logL) ,这部分修改的时间复杂度是 O(logLlogn) 。维护了哈希值就可以二分来算LCP了,所以一次修改的时间复杂度就是 O(logLlogn)
  查询的复杂度为 O(logn)
  总时间复杂度 O(mlogLlogn)
  其实不是很难写嘛就是常数有点爆炸而已

/*
    I will chase the meteor for you, a thousand times over.
    Please wait for me, until I fade forever.
    Just 'coz GEOTCBRL.
*/
#include 
using std::min;
using std::pair;
using std::make_pair;
#define fore(i,u)  for (int i = head[u] ; i ; i = nxt[i])
#define rep(i,a,b) for (int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for (int i = a , _ = b ; i >= _ ; i --)
#define For(i,a,b) for (int i = a , _ = b ; i <  _ ; i ++)
#define Dwn(i,a,b) for (int i = ((int) a) - 1 , _ = (b) ; i >= _ ; i --)
#define fors(s0,s) for (int s0 = (s) , _S = s ; s0 ; s0 = (s0 - 1) & _S)
#define foreach(it,s) for (__typeof(s.begin()) it = s.begin(); it != s.end(); it ++)

#define mp make_pair
#define pb push_back
#define pii pair
#define fir first
#define sec second
#define MS(x,a) memset(x , (a) , sizeof (x))

#define gprintf(...) fprintf(stderr , __VA_ARGS__)
#define gout(x) std::cerr << #x << "=" << x << std::endl
#define gout1(a,i) std::cerr << #a << '[' << i << "]=" << a[i] << std::endl
#define gout2(a,i,j) std::cerr << #a << '[' << i << "][" << j << "]=" << a[i][j] << std::endl
#define garr(a,l,r,tp) rep (__it , l , r) gprintf(tp"%c" , a[__it] , " \n"[__it == _])

template  inline void upmax(T&a , T b) { if (a < b) a = b ; }
template  inline void upmin(T&a , T b) { if (a > b) a = b ; }

typedef long long ll;

const int maxn = 50007;
const int maxS = 600007;
const int maxs = 1 << 17;
const int maxm = 15000007;
const int mod = 1000000007;
const int inf = 0x7fffffff;

typedef int arr[maxn];
typedef int adj[maxm];

#define gc getchar
#define idg isdigit
#define rd RD
#define rdll RD
template 
inline Type RD() {
    char c = getchar(); Type x = 0 , flag = 1;
    while (!idg(c) && c != '-') c = getchar();
    if (c == '-') flag = -1; else x = c - '0';
    while (idg(c = gc()))x = x * 10 + c - '0';
    return x * flag;
}
inline char rdch() {
    char c = gc();
    while (!isalpha(c)) c = gc();
    return c;
}
#undef idg
#undef gc

// beginning

#define uint unsigned int

uint pw1[maxS];

int n , m;

#define rnd rand

struct node {
    uint l , r;
    int sz , pri;
    uint val1;
    char c;

    node() {}

    node (char c): c(c) , sz(1) , pri(rnd()) {
        if (c) val1 = c - 'a';
        l = r = 0;
    }

    inline node operator+(node x) {
        node tmp;
        tmp.sz = sz + x.sz;
        tmp.val1 = (val1 + pw1[sz] * x.val1);
        return tmp;
    }
};

node nd[maxm];
int tot;

#define u nd[x]

#define lsz nd[u.l].sz
#define rsz nd[u.r].sz

inline void upd(uint x) {
    u.sz = 1 + lsz + rsz;
    node tmp = node(u.c) + nd[u.r];
    tmp = nd[u.l] + tmp;
    u.val1 = tmp.val1;
}

#undef u

inline uint newnode(char c) {
    int x = ++ tot;
    nd[x] = node(c);
    return x;
}

int join(int u , int v) {
    if (!u || !v) return u | v;
    int t = newnode(0);
    if (nd[u].pri < nd[v].pri) {
        nd[t] = nd[u];
        nd[t].r = join(nd[u].r , v);
    } else {
        nd[t] = nd[v];
        nd[t].l = join(u , nd[v].l);
    }
    upd(t);
    return t;
}

int sum(uint u , int k) {
    if (!k || !u) return 0;
    if (nd[nd[u].l].sz >= k)
        return sum(nd[u].l , k);
    else {
        int s = sum(nd[u].r , k - nd[nd[u].l].sz - 1);
        s = (s * pw1[1] + nd[u].c - 'a');
        s = (s * pw1[nd[nd[u].l].sz] + nd[nd[u].l].val1);
        return s;
    }
}

struct Treap {
    int rt;

    Treap() { rt = 0; }

    inline void merge(Treap &x) {
        rt = join(x.rt , rt);
    }
};

inline bool check(uint u , uint v , int k) {
    int x = sum(u , k) , y = sum(v , k);
    return x == y;
}

inline int LCP(Treap &x , Treap &b) {
    uint u = x.rt , v = b.rt;
    int l = 1 , r = min(nd[u].sz , nd[v].sz);
    int t = 0;
    while (l <= r) {
        int m = (l + r) >> 1;
        if (check(u , v , m))
            upmax(t , m) , l = m + 1;
        else
            r = m - 1;
    }
    return t;
}

inline void read(Treap &t) {
    static int sta[maxS];
    int top = 0 , pre;
    char c = getchar();
    while (!isalpha(c)) c = getchar();

    while (isalpha(c)) {
        pre = 0;
        int u = newnode(c);

        while (top && nd[sta[top]].pri > nd[u].pri) {
            upd(sta[top]);
            pre = sta[top --];
        }
        nd[u].l = pre;
        if (top) nd[sta[top]].r = u;
        sta[++ top] = u;

        c = getchar();
    }

    while (top) upd(sta[top --]);
    t.rt = sta[1];
}

Treap tag[maxs] , str[maxn] , s;
int val[maxs];
int ql , qr;

#define T int u = 1 , int l = 1 , int r = n 
#define L lc , l , m 
#define R rc , m + 1 , r 
#define lc (u << 1)
#define rc (u << 1 | 1)

void B(T) {
    if (l == r) {
        tag[u] = str[l];
        if (l != n)
            val[u] = LCP(str[l] , str[l + 1]);
        return;
    }
    int m = (l + r) >> 1;
    B(L) , B(R);
    val[u] = min(val[lc] , val[rc]);
}

inline void set_tag(int u , Treap t) {
    val[u] += nd[t.rt].sz;
    tag[u].merge(t);
}

inline void push(int u) {
    if (!tag[u].rt)
        return;
    set_tag(lc , tag[u]);
    set_tag(rc , tag[u]);
    tag[u] = Treap();
}

void modi(T) {
    if (ql <= l && r <= qr) {
        set_tag(u , s);
        return;
    }
    push(u);
    int m = (l + r) >> 1;
    if (ql <= m) modi(L);
    if (qr >  m) modi(R);
    val[u] = min(val[lc] , val[rc]);
}

Treap get(T) {
    if (l == r)
        return tag[u];
    push(u);
    int m = (l + r) >> 1;
    if (ql <= m)
        return get(L);
    return get(R);
}

void set(T) {
    if (l == r)
        return (void) (val[u] = qr);
    int m = (l + r) >> 1;
    push(u);
    if (ql <= m)
        set(L);
    else
        set(R);
    val[u] = min(val[lc] , val[rc]);
}

void add(T) {
    if (l == r)
        return (void) (set_tag(u , s));
    int m = (l + r) >> 1;
    push(u);
    if (ql <= m)
        add(L);
    else
        add(R);
    val[u] = min(val[lc] , val[rc]);
}

void input() {
    nd[0] = node(0) , nd[0].sz = 0;
    n = rd() , m = rd();
    pw1[0] = 1;
    rep (i , 1 , maxS - 7)
        pw1[i] = pw1[i - 1] * 41;
    rep (i , 1 , n)
        read(str[i]);
    B();
}

inline void reval(int l) {
    Treap t1 , t2;
    ql = l;
    t1 = get();

    ql = l + 1;
    t2 = get();

    ql = l , qr = LCP(t1 , t2);
    set();
}

inline void insert() {
    int l = rd() , r = rd();
    read(s);

    ql = r;
    add();
    if (l < r) {
        ql = l , qr = r - 1;
        modi();
    }

    if (l > 1)
        reval(l - 1);
    if (r < n)
        reval(r);
}

int que(T) {
    if (ql <= l && r <= qr)
        return val[u];
    int m = (l + r) >> 1 , t = inf;
    push(u);
    if (ql <= m) upmin(t , que(L));
    if (qr >  m) upmin(t , que(R));
    return t;
}

inline void query() {
    ql = rd() , qr = rd();
    int ans;
    if (ql == qr) {
        Treap t = get();
        ans = nd[t.rt].sz;
    } else {
        -- qr;
        ans = que();
    }
    printf("%d\n" , ans);
}

void solve() {
    rep (i , 1 , m) {
        char cmd = rdch();
        if (cmd == 'I')
            insert();
        else
            query();
    }
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
    #endif
    input();
    solve();
    return 0;
}

你可能感兴趣的:(线段树,字符串,treap,树套树)