您的位置:首页 > 其它

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

2016-12-25 19:15 260 查看
  蜜汁卡常卡过去了。。。

  考虑用线段树维护区间的LCP,如果设height[i]=LCP(S[i],S[i+1]),那么LCP(S[l]...S[r])=min(height[l]...height[r−1])。

  只要能快速维护height,就可以快速查询。

  于是考虑如何处理修改。

  可以发现区间加前缀的时候,[l...r−1]的height相当于直接加上了前缀的长度,而height[l−1]和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 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: