Live2D

题解「雅礼集训 2017 Day7」事情的相似度

题目传送门

Description

给出一个长度为 \(n\)\(01\) 串为 \(s\),设 \(t_i\)\(s_{1,2,..,i}\),有 \(m\) 次查询,每次查询给出 \(l,r\),求 \([l,r]\) 之间 \(t_i\) 的最长公共后缀长度的最大值。

\(n,m\le 10^5\)

Solution

本来不想写题解的,但想了想还是写一下吧。

不难想到,假设 \(f_i\)\(t_i\) 在后缀自动机上对应的点,那么就相当于查询:

\[\max\{\text{deep}(\text{lca}(f_i,f_j))\},l\le i,j\le r \]

考虑到在线不好搞,所以我们离线下来。然后你发现按左端点排序根本就不好做(不要问我怎么知道的),然后你发现按右端点排序之后就好做了。

我们可以在加入一个点的时候把 \(\text{parent}\) 树上都标记一下,那么如果过程中对于点 \(u\),如果已经标记过 \(i\) 了,那么说明对于当前右端点,左端点 \(\le i\) 的区间 \(u\) 都可以产生贡献,就可以树状数组修改一下。由此我们也可以看出,我们需要保存的是最新标记的标记。

复杂度显然是 \(\Theta(n\log^2n)\)

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 200005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

char s[MAXN];
int n,m,ans[MAXN];

struct Bit_Tree{
	int maxn[MAXN];
	int lowbit (int x){return x & (-x);}
	void modify (int x,int v){x = n - x + 1;for (Int i = x;i <= n;i += lowbit (i)) maxn[i] = max (maxn[i],v);}
	int query (int x){x = n - x + 1;int ans = 0;for (Int i = x;i;i -= lowbit (i)) ans = max (ans,maxn[i]);return ans;}
}T1;

struct node{
	int ind,qL,qR;
	bool operator < (const node &p)const{return qR < p.qR;}
};
vector <node> S[MAXN];

int lst = 1,cnt = 1,ch[MAXN][2],len[MAXN],git[MAXN],fail[MAXN];

void extend (int c){
	int f = lst,q = ++ cnt;lst = q,len[q] = len[f] + 1;
	while (f && !ch[f][c]) ch[f][c] = q,f = fail[f];
	if (!f) fail[q] = 1;
	else{
		int x = ch[f][c];
		if (len[x] == len[f] + 1) fail[q] = x;
		else{
			int p = ++ cnt;
			fail[p] = fail[x],len[p] = len[f] + 1,memcpy (ch[p],ch[x],sizeof (ch[p]));
			fail[x] = fail[q] = p;while (f && ch[f][c] == x) ch[f][c] = p,f = fail[f]; 
		}
	}
}

struct LCT{
	int id[MAXN],fa[MAXN],son[MAXN][2];
	bool rnk (int x){return son[fa[x]][1] == x;}
	bool Isroot (int x){return son[fa[x]][rnk(x)] != x;}
	void rotate (int x){
		int y = fa[x],z = fa[y],k = rnk(x),w = son[x][!k];
		if (!Isroot (y)) son[z][rnk(y)] = x;son[x][!k] = y,son[y][k] = w;
		if (w) fa[w] = y;fa[x] = z,fa[y] = x;
	}
	void Pushdown (int x){
		if (son[x][0]) id[son[x][0]] = id[x];
		if (son[x][1]) id[son[x][1]] = id[x];
	}
	void Pushall (int x){
		if (!Isroot (x)) Pushall (fa[x]);
		Pushdown (x); 
	}
	void Splay (int x){
		Pushall (x);
		while (!Isroot (x)){
			int y = fa[x];
			if (!Isroot (y)) rotate (rnk(x) == rnk(y) ? y : x);
			rotate (x); 
		}
	}
	void Access (int x,int now){
		for (Int y = 0;x;x = fa[y = x]){
			Splay (x);
			if (id[x]) T1.modify (id[x],len[x]);
			son[x][1] = y,id[x] = now; 
		}
	}
}T2;

signed main(){
	read (n,m),scanf ("%s",s + 1);
	for (Int i = 1;i <= n;++ i) extend (s[i] - '0'),git[i] = lst;
	for (Int i = 1,qL,qR;i <= m;++ i) read (qL,qR),S[qR].push_back (node{i,qL,qR});
	for (Int i = 1;i <= cnt;++ i) T2.fa[i] = fail[i];
	for (Int i = 1;i <= n;++ i){
		T2.Access (git[i],i);
		for (node g : S[i]) ans[g.ind] = T1.query (g.qL);  
	} 
	for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('\n');
	return 0;
}
posted @ 2021-03-22 20:23  Dark_Romance  阅读(34)  评论(0编辑  收藏  举报