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

来源:互联网 发布:上海国金网络朱文君 编辑:程序博客网 时间:2024/05/01 12:06

  蜜汁卡常卡过去了。。。
  考虑用线段树维护区间的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 <bits/stdc++.h>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<int , int>#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 <class T> inline void upmax(T&a , T b) { if (a < b) a = b ; }template <class T> 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<int>#define rdll RD<long long>template <typename Type>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 intuint pw1[maxS];int n , m;#define rnd randstruct 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].szinline 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 uinline 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;}
0 0
原创粉丝点击