21.7.7 t2
tag:扫描线,PAM,BIT
首先一个区间合法有两种情况:
- 存在一个长度大于 \(1\) 的奇回文串
- 被若干偶数回文串覆盖
这些回文串都必须在区间内
第一种情况很好处理,随便预处理一下。
主要是第二种情况。
直接做不太好做,可以改为判断,是否有一个位置没有被回文串覆盖。
对于一个点来说,有用的回文串只有,以它为左/右边界的最短的回文串,假设为 \([l_i,i]\) 和 \([i,r_i]\)。(由于我懒,所以用PAM扫了两遍)
那么对于 \(l\in(l_i,i],r\in[i,r_i)\) 的这些询问,\(i\) 这个位置就没有被任何回文串覆盖。
然后可以对于每个点,把限制看作一个矩形,一个询问就是一个点,那么一个询问合法当且仅当它不被任何矩形包含。
扫描线一下即可。
当 \(l_i/r_i\) 不存在时可以设为 \(0/n+1\)。
#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 = 1000005
};
char s[MAXN], a[MAXN];
struct node{
int son[26], fa, len, mn;
#define son(x,opt) t[x].son[opt]
#define fa(x) t[x].fa
#define len(x) t[x].len
#define mn(x) t[x].mn
}t[MAXN];
int node_cnt=1;
inline int Find(int x, int r){
while(s[r-len(x)-1]!=s[r]) x = fa(x);
return x;
}
int prv=1;
inline int insert(int r){
prv = Find(prv,r); int now = son(prv,s[r]-'a');
if(!now){
now = ++node_cnt;
mn(now) = len(now) = len(prv)+2;
fa(now) = son(Find(fa(prv),r),s[r]-'a');
son(prv,s[r]-'a') = now;
if(mn(fa(now))>1) mn(now) = min(mn(now),mn(fa(now)));
}
return prv=now;
}
inline void init(){
len(1) = -1; fa(0) = 1; fa(1) = 1;
node_cnt = prv = 1;
}
int n, Q, l[MAXN], r[MAXN], S[MAXN];
char ans[MAXN];
struct upd{
int x, l, r, opt;
inline bool operator <(const upd &k)const{return x!=k.x?x<k.x:opt<k.opt;}
}q[MAXN*3];
int qcnt;
namespace BIT{
#define lowbit(x) (x&-x)
int t[MAXN];
inline void Add(int x, int k){for(;x<=n;x+=lowbit(x))t[x]+=k;}
inline void Add(int l, int r, int k){Add(l,k);Add(r+1,-k);}
inline int Query(int x){int res=0;for(;x;x-=lowbit(x))res+=t[x];return res;}
#undef lowbit
}
using BIT::Add;
using BIT::Query;
int main(){
Read(n); scanf("%s",a+1); Read(Q);
for(int i=2; i<n; i++) S[i] = S[i-1]+(a[i-1]==a[i+1]);
init(); for(int i=1; i<=n; i++) s[i] = a[i];
for(int i=1; i<=n; i++) l[i] = i-mn(insert(i))+1;
init(); for(int i=1; i<=n; i++) s[i] = a[n-i+1];
for(int i=n; i; i--) r[i] = i+mn(insert(n-i+1))-1;
for(int i=1; i<=n; i++){
if(l[i]==i) l[i] = 0;
if(r[i]==i) r[i] = n+1;
q[++qcnt] = (upd){l[i]+1,i,r[i]-1,0};
q[++qcnt] = (upd){i,i,r[i]-1,Q+1};
}
for(int i=1; i<=Q; i++){
int L, R; ans[i] = '0';
Read(L); Read(R);
if(L==R) continue;
if(S[R-1]^S[L]) ans[i] = '1';
else q[++qcnt] = (upd){L,R,R-L+1,i};
}
sort(q+1,q+qcnt+1);
for(int i=1; i<=qcnt; i++){
if(q[i].opt==0) Add(q[i].l,q[i].r,1);
else if(q[i].opt==Q+1) Add(q[i].l,q[i].r,-1);
else ans[q[i].opt] = '0'+!Query(q[i].l);
}
cout<<ans+1<<'\n';
return 0;
}