P11823 [湖北省选模拟 2025] 最后的台词 / lines 题解
先考虑
设一个串
对于固定的
于是问题又变成区间覆盖父亲,区间查某个点一直往上跳要跳几步才小于某个给定值,这个可以 LCT 维护,每次区间覆盖只修改连续段最左边点的父亲,其他的可以以 0 的边权连左边节点,每次 access 然后平衡树上二分即可,时间复杂度
如果你不想写 LCT,可以考虑分块,区间覆盖小块暴力,大块打 tag,你需要对没打过 tag 的块预处理每个点第一次跳出块的位置和贡献,查询直接贪心跳即可,由于数据很水也可以通过。
提供个分块代码,写的时候没动脑子,实现比较呃呃,不太建议参考。
#include<bits/stdc++.h>
#define vi vector<int>
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define pi pair<int,int>
#define ll long long
#define IL inline
#define For(i,j,k) for(int i=(j);i<=(k);i++)
#define Fol(i,j,k) for(int i=(j);i>=(k);i--)
#define fi first
#define se second
using namespace std;
#define N 2000005
#define inf 0x3f3f3f3f
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9')f=(ch=='-'?-1:f),ch=getchar();
while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x*f;
}
void write(ll x){
if(x<0)putchar('-'),x=-x;
if(x/10)write(x/10);
putchar(x%10+'0');
}
void debug(auto ...x){
((cerr<<x<<' '),...);
cerr<<endl;
}
char s[N];
map<pi,int> t;
vector<array<int,3> > Q[N];
vector<pi> P[N];
namespace SAM{
int nex[N][26],len[N],fa[N],mned[N],mxed[N],las,cnt,lasp[N];
int f[21][N];
basic_string<int> e[N];
vi S[N];
void extend(int it,int d){
int cur=++cnt,p=las;len[cur]=len[p]+1;mxed[cur]=mned[cur]=d;las=cur;S[cur].pb(d);lasp[d]=cur;
while(!nex[p][it])nex[p][it]=cur,p=fa[p];
if(!p)return fa[cur]=1,void();
int q=nex[p][it];
if(len[q]==len[p]+1)return fa[cur]=q,void();
int cl=++cnt;memcpy(nex[cl],nex[q],sizeof(nex[q]));len[cl]=len[p]+1;
fa[cl]=fa[q];fa[q]=fa[cur]=cl;
while(nex[p][it]==q)nex[p][it]=cl,p=fa[p];
}
void init(){
For(i,1,cnt)if(fa[i])e[fa[i]]+=i,f[0][i]=fa[i];
For(i,1,__lg(cnt))For(j,1,cnt)f[i][j]=f[i-1][f[i-1][j]];
auto dfs=[&](auto &&self,int x)->void {
if(!mxed[x])mxed[x]=0,mned[x]=0x3f3f3f3f;
for(auto v:e[x]){
self(self,v);mxed[x]=max(mxed[x],mxed[v]);
mned[x]=min(mned[x],mned[v]);
}
P[len[x]].eb(mned[x],mxed[x]);
};
dfs(dfs,1);
}
pi jump(int x,int k){
int now=lasp[x];
if(len[now]>=k && len[fa[now]]<k)return mp(now,mned[now]);
Fol(i,__lg(cnt),0)if(f[i][now] && len[f[i][now]]>=k)now=f[i][now];
return mp(now,mned[now]);
}
}
int f[N],ans[N];
int n;
struct Block{
int a[N],tag[N],b[N],len[N];
#define B 505
void rebuild(int id){
int l=id*B+1,r=min((id+1)*B,n);
if(f[r]<l)return;
For(i,l,r){
if(a[i]<l)b[i]=a[i],len[i]=1;
else if(a[i]==i)b[i]=i,len[i]=0;
else b[i]=b[a[i]],len[i]=len[a[i]]+1;
}
}
void upd(int l,int r){
if(l>r)return;
int Bl=(l-1)/B,Br=(r-1)/B;
if(Bl==Br){
if(tag[Bl]<l)return;
Fol(i,r,l){
a[i]=min(a[i],l);
if(tag[Bl]!=inf && a[i]<l)return;
}
rebuild(Bl);return;
}
For(i,l,(Bl+1)*B)a[i]=min(a[i],l);
For(i,Br*B+1,r)a[i]=min(a[i],l);
if(tag[Bl]==inf)rebuild(Bl);
if(tag[Br]==inf)rebuild(Br);
For(i,Bl+1,Br-1)tag[i]=min(tag[i],l);
}
int ljump(int now,int goal){
int res=0;
while(now>goal){
if(min(a[now],tag[(now-1)/B])==now)return -1;
now=min(a[now],tag[(now-1)/B]);res++;
}
return res;
}
int bjump(int now,int goal){
int res=0;
while(now>goal){
if(tag[(now-1)/B]!=inf)now=min(tag[(now-1)/B],a[now]),res++;
else if(b[now]>=goal && b[now]!=now)res+=len[now],now=b[now];
else{
int ans=ljump(now,goal);
if(ans==-1)return -1;
return ans+res;
}
}
return res;
}
#undef B
}Blo;
int main(){
//freopen("lines5.in","r",stdin);
//freopen("lines5.out","w",stdout);
scanf("%s",s+1);n=strlen(s+1);SAM::las=SAM::cnt=1;
int q=read();
For(i,1,n)SAM::extend(s[i]-'a',i);SAM::init();
For(i,1,q){
int l1=read(),r1=read(),l2=read(),r2=read(),k=read();
if(r1-l1==r2-l2 && SAM::jump(r1,r1-l1+1).fi==SAM::jump(r2,r1-l1+1).fi){ans[i]=1;continue;}
Q[k].pb(array<int,3>{r1,l2+k-1,i});
}
For(i,0,n)f[i]=i,Blo.tag[i]=inf,Blo.a[i]=Blo.b[i]=i;
Fol(k,n,1){
for(auto [l,r]:P[k]){
Blo.upd(l,r);
}
for(auto [now,goal,id]:Q[k]){
pi A=SAM::jump(now,k),B=SAM::jump(goal,k);B.se=SAM::mxed[B.fi];
if(A.fi==B.fi){ans[id]=2;continue;}
now=A.se;goal=B.se;
if(now<=goal){ans[id]=3;continue;}
int res=Blo.bjump(now,goal);
if(res==-1)ans[id]=-1;
else ans[id]=res+3;
}
}
For(i,1,q)write(ans[i]),putchar('\n');
return 0;
}