21.7.2 t2
阿新 • • 發佈:2021-07-02
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; }