p5829 【模板】失配樹
參考題解
我們先想乙個問題:如何求出乙個字串的所有border?
如果乙個字串既是 s的字首又是 s 的字尾,那麼我們把 ss 自己平移一下就可以前後重合,然後我們就可以繼續匹。。。。。這不就是kmp嗎
求兩個字首的最長公共border,
先對原串進行kmp,通過跳兩個字首的next求到兩個字首的所有border
我們通過next陣列構建一棵樹(發現這就是只有乙個字串的ac自動機的fail樹,所有我們也叫它fail樹),容易發現兩個字首的最長公共border就是他們在fail樹上的lca
綜上所述:
對原串kmp一遍,求的next陣列
構建fail樹
在fail數上跑lca
#include
#include
#include
#include
#include
#include
using
namespace std;
#define set(a) memset(a,0,sizeof(a))
#define f(i,a,b) for(register int i=a,i##end=b;i<=i##end;++i)
#define uf(i,a,b) for(register int i=a,i##end=b;i>=i##end;--i)
#define openf(a) freopen(#a
".in"
,"r"
,stdin)
;freopen
(#a".out"
,"w"
,stdout)
#define re register
#define ri re int
#define il inline
typedef long
long ll;
typedef unsigned long
long ull;
template inline t
rd(t& x)
ll rd()
inline int
max(
int a,
int b)
inline int
min(
int a,
int b)
const
int inf=
1<
<30;
const
int n=
1000005
;int next[n]
,n,m;
char s[n]
;int fa[n]
;int
get(
int x)
void
merge
(int x,
int y)
bool vis[n]
;int head[n]
,to[
2*n]
,nxt[
2*n]
,tot;
void
add(
int u,
int v)
//graph
int head2[n]
,to2[
2*n]
,nxt2[
2*n]
,num[
2*n]
,tot2;
void
add2
(int u,
int v,
int w)
//query
int ans[n]
,x[n
],y[n]
;void
tarjan
(int x)
for(ri i=head2[x]
;i;i=nxt2[i])if
(vis[to2[i]
]) ans[num[i]]=
get(to2[i]);
}int
main()
f(i,
1,n)
add(next[i]
,i);
rd(m);f
(i,1
,m)tarjan(0
);f(i,
1,m)
printf
("%d\n"
,(ans[i]
==x[i]
||ans[i]
==y[i]
)?next[ans[i]
]:ans[i]);
return0;
}
P5829 模板 失配樹
p5829 模板 失配樹 求公共 border 求 border 我會,kmp 那麼我直接做 m 次 kmp。顯然會tle,但是我們也可以用 kmp 先求一下原串的 border 然後我們可以發現,border 的 border 也是 border 那麼我們可以利用這個關係建一棵樹,然後我們可以發現...
P5829 模板 失配樹
目錄雖然不知道失配樹是什麼,看這題是為數不多的kmp練手的 能做的題 之一,就把這道題切了 傳送門個人覺得題目已經非常簡潔明瞭,感動,就不再重複題意 kmp lca 先推一道題,對這題應該有幫助 傳送門 kmp中,next i 是由next 1 i 1 得到的,若next i 由next j 得到,...
洛谷P5829 失配樹
給定一長為 n n leq 10 6 的字串 s m m leq 5 times 10 5 次詢問,每次詢問它的兩個字首的最長公共 border。先跑一遍kmp求出 fail 陣列,每個 pos 向 fail pos 連邊,建出 fail 樹,在 fail 樹上求lca即為兩個字首的最長公共bord...