【LOJ】#2525. 「HAOI2018」字串覆盖

题解

写后缀树真是一写就好久,然后调好久QAQ

我们把两个串取反拼一起建后缀树,这样的话使得后缀树是正串的后缀树

然后我们把询问挂在每个节点上,每次线段树合并,对于大于50的每次暴力跳着在线段树找,对于小于50的建出一棵树来,也就是(a[i][j])表示第(i)位往后(j)位,向下一个(a[t][j])(t >= j)连一条边
这是一棵树,在树上倍增就行了

说起算法来很容易吧!!!!写起来特别烦QAQ

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('
')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 100005
#define mo 974711
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 + c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
int N,LA,LB,c[MAXN * 2],Ncnt,F = 50;
int64 K;
char A[MAXN],B[MAXN];
int fa[MAXN * 4][19],up[MAXN * 4][19];
struct node {
    int cnt,len;
    node *nxt[26],*par;
}pool[MAXN * 4],*tail = pool,*root,*last,*que[MAXN * 4];
vector<pii > son[MAXN * 4];
vector<int> sm[MAXN * 4];
int ed[MAXN * 4],posA[MAXN],posB[MAXN],dis[MAXN * 4];
int64 ans[MAXN],sum[MAXN * 4][19];
struct qry_node {
    int s,t,len,id;
    friend bool operator < (const qry_node &a,const qry_node &b) {
	return a.len < b.len;
    }
};
vector<qry_node> Qry[MAXN * 4];
namespace segtr {
    struct node {
	int minv,lc,rc;
    }tr[MAXN * 20];
    int Ncnt = 0,rt[MAXN * 4];
#define LC(u) tr[u].lc
#define RC(u) tr[u].rc
#define MIN(u) tr[u].minv
    void update(int u) {
	MIN(u) = LA + 1;
	if(LC(u)) {
	    MIN(u) = min(MIN(u),MIN(LC(u)));
	}
	if(RC(u)) {
	    MIN(u) = min(MIN(u),MIN(RC(u)));
	}
    }
    void Insert(int &u,int L,int R,int v) {
	if(!u) u = ++Ncnt;
	if(L == R) {MIN(u) =  v;return;}
	int mid = (L + R) >> 1;
	if(v <= mid) Insert(LC(u),L,mid,v);
	else Insert(RC(u),mid + 1,R,v);
	update(u);
    }
    int Merge(int u,int v) {
	if(!u) return v;
	if(!v) return u;
	LC(u) = Merge(LC(u),LC(v));
	RC(u) = Merge(RC(u),RC(v));
	update(u);
	return u;
    }
    int Query(int u,int L,int R,int p) {
	if(!u) return LA + 1;
	if(L >= p) return MIN(u);
	int mid = (L + R) >> 1;
	if(p <= mid) return min(Query(LC(u),L,mid,p),MIN(RC(u)) != 0 ? MIN(RC(u)) : LA + 1);
	else return Query(RC(u),mid + 1,R,p);
    }
}
using segtr::rt;
using segtr::Insert;
using segtr::Merge;
using segtr::Query;
void build_SAM(int c,int len) {
    node *nowp = tail++,*p;
    nowp->len = len;nowp->cnt = 1;
    for(p = last ; p && !p->nxt[c] ; p = p->par) {
	p->nxt[c] = nowp;
    }
    if(!p) nowp->par = root;
    else {
	node *q = p->nxt[c];
	if(q->len == p->len + 1) nowp->par = q;
	else {
	    node *copyq = tail++;
	    *copyq = *q;copyq->cnt = 0;copyq->len = p->len + 1;
	    q->par = nowp->par = copyq;
	    for(; p && p->nxt[c] == q ; p = p->par) {
		p->nxt[c] = copyq;
	    }
	}
    }
    last = nowp;
}
void build_SuffixTree() {
    int m = tail - pool;
    Ncnt = m;
    for(int i = 0 ; i < m ; ++i) {
	c[pool[i].len]++;
    }
    for(int i = 1 ; i <= LA + LB ; ++i) c[i] += c[i - 1];
    for(int i = 0 ; i < m ; ++i) {
	que[c[pool[i].len]--] = &pool[i];
    }
    for(int i = 1 ; i <= m ; ++i) {
	int f = que[i]->par - pool + 1;
    }
    for(int i = m ; i > 1 ; --i) {
	int u = que[i] - pool + 1;
	int f = que[i]->par - pool + 1;
	fa[u][0] = f;
	son[f].pb(mp(u,que[i]->len - que[i]->par->len));
	if(que[i]->cnt) {
	    if(que[i]->len <= LA) {
		ed[u] = LA - que[i]->len + 1;
		posA[LA - que[i]->len + 1] = u;
	    }
	    else posB[LB - (que[i]->len - LA) + 1] = u;
	}
    }
}
void dfs(int u) {
    int s = son[u].size();
    for(int i = 0 ; i < s ; ++i) {
	dis[son[u][i].fi] = dis[u] + son[u][i].se;
	dfs(son[u][i].fi);
    }
}
void Process(int u) {
    int s = son[u].size(),t;
    for(int i = 0 ; i < s ; ++i) {
	Process(son[u][i].fi);
	rt[u] = Merge(rt[u],rt[son[u][i].fi]);
    }
    if(ed[u]) Insert(rt[u],1,LA,ed[u]);
    sort(Qry[u].begin(),Qry[u].end());
    if(sm[u].size()) sort(sm[u].begin(),sm[u].end());
    s = Qry[u].size(),t = sm[u].size();
    for(int i = 0 ; i < s ; ++i) {
	if((i == 0 || Qry[u][i].len != Qry[u][i - 1].len) && Qry[u][i].len <= F) {
	    int r = 0;
	    for(int j = 0 ; j < t ; ++j) {
		while(r < t && sm[u][r] - sm[u][j] < Qry[u][i].len) ++r;
		sum[sm[u][j]][0] = 0;
		if(r >= t) up[sm[u][j]][0] = 0;
		else {up[sm[u][j]][0] = sm[u][r];sum[sm[u][j]][0] = sm[u][r];}
	    }
	    for(int k = 1 ; k <= 18 ; ++k) {
		for(int j = 0 ; j < t ; ++j) {
		    up[sm[u][j]][k] = up[up[sm[u][j]][k - 1]][k - 1];
		    sum[sm[u][j]][k] = sum[sm[u][j]][k - 1] + sum[up[sm[u][j]][k - 1]][k - 1];
		}
	    }
	}
	if(Qry[u][i].len <= F) {
	    int h = Query(rt[u],1,LA,Qry[u][i].s);
	    if(h + Qry[u][i].len - 1 <= Qry[u][i].t) {
		ans[Qry[u][i].id] += K - h;
		for(int k = 18 ; k >= 0 ; --k) {
		    if(up[h][k]) {
			if(up[h][k] + Qry[u][i].len - 1 <= Qry[u][i].t) {
			    ans[Qry[u][i].id] += K * (1 << k) - sum[h][k];
			    h = up[h][k];
			}
		    }
		}
	    }
	}
	else {
	    int h,le = Qry[u][i].s;
	    while(1) {
		h = Query(rt[u],1,LA,le);
		if(h + Qry[u][i].len - 1 <= Qry[u][i].t) {
		    ans[Qry[u][i].id] += K - h;
		    le = h + Qry[u][i].len;
		}
		else break;
	    }
	}
    }
}
void Solve() {
    read(N);read(K);
    root = last = tail++;
    scanf("%s",A + 1);scanf("%s",B + 1);
    LA = strlen(A + 1);LB = strlen(B + 1);
    int tot = 0;
    for(int i = LA ; i >= 1 ; --i) {
	build_SAM(A[i] - 'a',++tot);
    }
    for(int i = LB ; i >= 1 ; --i) {
	build_SAM(B[i] - 'a',++tot);
    }
    build_SuffixTree();
    for(int j = 1 ; j <= 18 ; ++j) {
	for(int i = 1 ; i <= Ncnt ; ++i) {
	    fa[i][j] = fa[fa[i][j - 1]][j - 1];
	}
    }
    int s,t,l,r,q;
    dfs(1);
    read(q);
    for(int i = 1 ; i <= q ; ++i) {
	read(s);read(t);read(l);read(r);
	int h = posB[l];
	for(int j = 18 ; j >= 0 ; --j) {
	    if(dis[fa[h][j]] >= (r - l + 1)) h = fa[h][j];
	}
	Qry[h].pb((qry_node){s,t,r - l + 1,i});
    }
    for(int i = 1 ; i <= LA ; ++i) {
	int t = posA[i];
	for(int j = 18 ; j >= 0 ; --j) {
	    if(dis[fa[t][j]] >= F) t = fa[t][j];
	}
	while(t) {
	    sm[t].pb(i);
	    t = fa[t][0];
	}
    }
    Process(1);
    for(int i = 1 ; i <= q ; ++i) {
	out(ans[i]);enter;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}
原文地址:https://www.cnblogs.com/ivorysi/p/10049894.html