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;
}
posted @ 2021-07-07 19:38  oisdoaiu  阅读(29)  评论(0编辑  收藏  举报