1. 程式人生 > 其它 >21.7.2 t2

21.7.2 t2

tag:SAM,LCT,線段樹


LCT+SAM維護endpos套路,先建出SAM,然後從左到右Access(pos[i])的同時處理詢問。

每次Access的時候到根鏈會分成若干段,每段的endpos相同,所以對於這個點代表的某個串來說,當詢問的 \(l\le endpos-len+1\) 時,這個串就可以對詢問區間產生貢獻。

具體來說,假設當前點代表的最長串為 \([x,endpos]\),那麼

  • \(l\in[x,endpos]\),貢獻為 \(endpos-l+1\)
  • \(l<x\),貢獻為 \(endpos-x+1\)

所以用線段樹維護每個點的 \(mxendpos\)\(mxans\)

即可。

由於要將到根鏈的endpos都改為i,所以LCT的splay要支援區間覆蓋。


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

template<typename T>
inline void Read(T &n){
	char ch; bool flag=false;
	while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
	for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
	if(flag)n=-n;
}

enum{
	MAXN = 100005
};

int n, Q, curpos;
char a[MAXN];

namespace SGT{
	struct node{
		int ans, mxr;
		node(int ans=0, int mxr=0):ans(ans),mxr(mxr){}
		#define ans(x) t[x].ans
		#define mxr(x) t[x].mxr
	}t[MAXN<<2];

	inline int lc(int x){return x<<1;}
	inline int rc(int x){return x<<1|1;}

	void Update(int x, int head, int tail, int l, int r, int ans, int mxr){
		if(l<=head and tail<=r) return ans(x) = max(ans(x),ans), mxr(x) = max(mxr(x),mxr), void();
		int mid = head+tail >> 1;
		if(l<=mid) Update(lc(x),head,mid,l,r,ans,mxr);
		if(mid<r) Update(rc(x),mid+1,tail,l,r,ans,mxr);
	}

	inline pair<int,int> Query(int pos){
		int x=1, head=1, tail=n, ans=ans(1), mxr=mxr(1);
		while(head<tail){
			int mid = head+tail >> 1;
			if(pos<=mid) x = lc(x), tail = mid;
			else x = rc(x), head = mid+1;
			ans = max(ans,ans(x));
			mxr = max(mxr,mxr(x));
		}
		return make_pair(ans,mxr);
	}
}
using SGT::Update;
using SGT::Query;

namespace LCT{
	struct node{
		int fa, son[2], val, mx, ed, fil;
		#define fa(x) t[x].fa
		#define lc(x) t[x].son[0]
		#define rc(x) t[x].son[1]
		#define val(x) t[x].val
		#define mx(x) t[x].mx
		#define ed(x) t[x].ed
		#define fil(x) t[x].fil
	}t[MAXN<<1];

	inline char Is_Root(int x){return lc(fa(x))!=x and rc(fa(x))!=x;}
	inline char Which(int x){return rc(fa(x))==x;}

	inline void Push_Up(int x){
		mx(x) = val(x);
		if(lc(x)) mx(x) = max(mx(lc(x)),mx(x));
		if(rc(x)) mx(x) = max(mx(rc(x)),mx(x));
 	}

	inline void Fill(int x, int fil){fil(x) = ed(x) = fil;}

	inline void Push_Down(int x){
		if(fil(x)){
			if(lc(x)) Fill(lc(x),fil(x));
			if(rc(x)) Fill(rc(x),fil(x));
			fil(x) = 0;
		}
	}

	inline void Rotate(int x){
		int y=fa(x), z=fa(y), k=Which(x), u=t[x].son[!k];
		if(!Is_Root(y)) t[z].son[Which(y)]=x; fa(x)=z;
		if(u) fa(u)=y; t[y].son[k]=u;
		fa(y)=x; t[x].son[!k]=y;
		Push_Up(y); Push_Up(x);
	}

	inline void Splay(int x){
		static int q[MAXN<<1], top;
		q[top=1] = x; for(int i=x; !Is_Root(i); i=fa(i)) q[++top] = fa(i);
		for(int i=top; i; i--) Push_Down(q[i]);

		while(!Is_Root(x)){
			int y=fa(x);
			if(!Is_Root(y)) Rotate(Which(x)==Which(y)?y:x);
			Rotate(x);
		}
	}

	inline void Access(int x){
		int tx=x;
		for(int y=0; x; y=x, x=fa(x)){
			Splay(x);
			rc(x) = 0; Push_Up(x);
			if(ed(x) and mx(x)){
				int l=ed(x)-mx(x)+1, r=ed(x);
				if(l>1) Update(1,1,n,1,l-1,r-l+1,0);
				Update(1,1,n,l,r,0,r);
			}
			rc(x) = y; Push_Up(x);
		}
		Splay(tx); Fill(tx,curpos);
		assert(lc(1)==0);
	}
}

struct node{
	int fa, son[26], len;
	#define son(x,opt) t[x].son[opt]
	#define len(x) t[x].len
}t[MAXN<<1];
int node_cnt=1, prv=1;

inline int insert(char v){
	int x = ++node_cnt; len(x) = len(prv)+1;
	while(prv and !son(prv,v)) son(prv,v) = x, prv = fa(prv);
	if(!prv) fa(x) = 1;
	else{
		int p = son(prv,v);
		if(len(p) == len(prv)+1) fa(x) = p;
		else{
			int new_p = ++node_cnt; len(new_p) = len(prv)+1;
			fa(new_p) = fa(p); fa(p) = fa(x) = new_p;
			copy(t[p].son,t[p].son+26,t[new_p].son);
			while(prv and son(prv,v)==p) son(prv,v) = new_p, prv = fa(prv);
		}
	}
	return prv=x;
}

struct quest{
	int l, r, id;
	inline bool operator <(const quest &k)const{return r<k.r;}
}q[MAXN];
int ans[MAXN], pos[MAXN];

int main(){
	// freopen("2.in","r",stdin);
	scanf("%s",a+1); n = strlen(a+1); Read(Q);
	for(int i=1; i<=Q; i++) Read(q[i].l), Read(q[i].r), q[i].id = i;
	sort(q+1,q+Q+1);
	for(int i=1; i<=n; i++) pos[i] = insert(a[i]-'a');
	for(int i=2; i<=node_cnt; i++) LCT::fa(i) = fa(i), LCT::mx(i) = LCT::val(i) = len(i);
	for(int i=1, it=1; i<=n; i++){
		curpos = i;
		LCT::Access(pos[i]);
		while(it<=Q and q[it].r==i){
			pair<int,int> tmp = Query(q[it].l);
			ans[q[it].id] = max(tmp.first,tmp.second-q[it].l+1);
			it++;
		}
	}
	for(int i=1; i<=Q; i++) printf("%d\n",ans[i]);
	return 0;
}