字符串+置换+莫队离线处理——cf1290B

/*
题意可以转化为通过s[l..r]构造出新的串t[l..r]和s不能约
    t[l..r]的每个前缀,每个后缀的字符数量都必须和s[l..r]对应的前后缀字符数量不同 
构造策略:
    如果s[l]!=s[r]直接交换即可
    否则找到s[i]!=s[j],swap(s[i],s[r]),swap(s[j],s[l]),即此时只要s[l..r]有三种不同的字符即可 
所以统计每个区间内出现的字符种数即可 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 300005

int block,n,q,ans[N];
char s[N];
struct Query{
    int l,r,id,tot;
}Q[N];
int cmp(Query a,Query b){
    if(a.l/block==b.l/block)return a.r<b.r;
    return a.l<b.l; 
}

int cnt[26],tot;
void add(int x){
    cnt[s[x]-'a']++;
    if(cnt[s[x]-'a']==1)tot++;
}
void del(int x){
    cnt[s[x]-'a']--;
    if(cnt[s[x]-'a']==0)tot--;
}

int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    cin>>q;
    for(int i=1;i<=q;i++){
        cin>>Q[i].l>>Q[i].r;
        Q[i].id=i;
    }
    /*if(n>200){
        cout<<Q[14].l<<" "<<Q[14].r<<'
';
        for(int i=25336;i<=25341;i++)cout<<s[i];
        
    }*/
    block=sqrt(n);
    sort(Q+1,Q+1+q,cmp);
    
    int L=1,R=0;
    for(int i=1;i<=q;i++){
        while(R<Q[i].r)add(++R);
        while(L>Q[i].l)add(--L);
        while(R>Q[i].r)del(R--);
        while(L<Q[i].l)del(L++);
        Q[i].tot=tot;
    }
    
    for(int i=1;i<=q;i++){
        int l=Q[i].l,r=Q[i].r;
        if(s[l]!=s[r] || l==r)ans[Q[i].id]=1;
        else if(Q[i].tot>=3)ans[Q[i].id]=1;
    }
    
    for(int i=1;i<=q;i++)
        if(ans[i])puts("YES");
        else puts("NO");
}
原文地址:https://www.cnblogs.com/zsben991126/p/12270046.html