Codeforces 1037 H. Security

\(>Codeforces \space 1037\ H. Security<\)

题目大意 : 有一个串 \(S\)\(q\) 组询问,每一次给出一个询问串 \(T\) 和一个区间 \([l,r]\) ,要求找出 \(S\)\([l,r]\) 之间的子串中字典序大于 \(T\) 且最小的

\(1 \leq |S|\leq 10^5, 1\leq q \leq 2 \times 10^5\)

解题思路 :

其实这个题一点意思都没有,就是一个 \(sam\) + 线段树合并裸题..

但是某位不得了的指导大人近期 \(AC\) 了此题,于是我就去顺手做了一下

考虑每次把询问串在 \(sam\) 上匹配,对于每一个在 \(sam\) 上出现的 \(T\) 的合法前缀,大力算出能否在后面加一个字符满足比 \(T\) 大且在 \(L, R\) 区间

后者线段树合并维护即可

/*program by mangoyang*/
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
	int ch = 0, f = 0; x = 0;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
	if(f) x = -x;
}
const int N = 1000005;
char s[N]; int n;
struct SegmentTree{
	int sz[N*25], lc[N*25], rc[N*25], size;
	inline void ins(int &u, int l, int r, int pos){
		if(!u) u = ++size;
		if(l == r) return (void) (sz[u]++);
		int mid = l + r >> 1;
		if(pos <= mid) ins(lc[u], l, mid, pos);
		else ins(rc[u], mid + 1, r, pos); sz[u] = sz[lc[u]] + sz[rc[u]];
	}
	inline int merge(int x, int y, int l, int r){
		if(!x || !y) return x + y;
		int o = ++size, mid = l + r >> 1;
		if(l == r) sz[o] = sz[x] + sz[y];
		else{
			lc[o] = merge(lc[x], lc[y], l, mid);
			rc[o] = merge(rc[x], rc[y], mid + 1, r);
			sz[o] = sz[lc[o]] + sz[rc[o]];
		}
		return o;
	}
	inline int query(int u, int l, int r, int L, int R){
		if(!u || l > r) return 0;
		if(l >= L && r <= R) return sz[u];
		int mid = l + r >> 1, res = 0;
		if(L <= mid) res += query(lc[u], l, mid, L, R);
		if(mid < R) res += query(rc[u], mid + 1, r, L, R); 
		return res;
	}
}Seg;
struct SaffixAutomaton{
	vector<int> g[N];
	int ch[N][26], dep[N], rt[N], fa[N], size, tail;
	inline SaffixAutomaton(){ size = tail = 1; }
	inline int newnode(int x){ return dep[++size] = x, size; }
	inline void ins(int c, int pos){
		int p = tail, np = newnode(dep[p] + 1);
		Seg.ins(rt[np], 1, n, pos);
		for(; !ch[p][c] && p; p = fa[p]) ch[p][c] = np;
		if(!p) return (void) (fa[np] = 1, tail = np);
		int q = ch[p][c];
		if(dep[q] == dep[p] + 1) fa[np] = q;
		else{
			int nq = newnode(dep[p] + 1); 
			fa[nq] = fa[q], fa[q] = fa[np] = nq;
			for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
			for(; ch[p][c] == q && p; p = fa[p]) ch[p][c] = nq;
		}tail = np;
	}
	inline void dfs(int u){
		for(int i = 0; i < g[u].size(); i++){
			int v = g[u][i];
			dfs(v), rt[u] = Seg.merge(rt[u], rt[v], 1, n);
		}
	}
	inline void Prework(){ 
		for(int i = 1; i <= size; i++) g[fa[i]].push_back(i); dfs(1); 
	}
	inline void solve(char *s, int l, int r){
		int len = strlen(s + 1), p = 1, pos = 0, res = 0;
		for(int i = 1; i <= len + 1; i++){
			int c = i > len ? (-1) : (s[i] - 'a'), flg = 0;
			for(int j = c + 1; j < 26; j++) if(ch[p][j]){
				int u = ch[p][j];
				if(Seg.query(rt[u], 1, n, l + i - 1, r)){
					res = j + 'a', pos = i - 1; break;
				}
			}
			if(ch[p][c]) p = ch[p][c]; else break;
		}
		if(!res) return (void) puts("-1");
		for(int i = 1; i <= pos; i++) putchar(s[i]);
		putchar(res), putchar('\n');
	}
}van;
int main(){
	scanf("%s", s + 1); n = strlen(s + 1);
	for(int i = 1; i <= n; i++) van.ins(s[i] - 'a', i); 
	van.Prework(); int Q;  read(Q);
	for(int i = 1, l, r; i <= Q; i++)
		read(l), read(r), scanf("%s", s + 1), van.solve(s, l, r);
	return 0;
}


posted @ 2018-09-13 22:27  Joyemang33  阅读(434)  评论(0编辑  收藏  举报