题目的意思是,字符串S的一个子串X,是否是字符串S排序后字符串T的字串?
首先,符合要求,字符串X必须是不递减的,这样才可能跟不递减的S有重合部分。
其次,X中除了最大、最小的字符外,其他字符不能出现在两边,否则S排序后,这些字符就会插入到X中。
是否递增可以用线段树维护;保证单调性的前提下,字符数量可以用二分查找统计。

#include <bits/stdc++.h>
const int N=1<<18|9;
using namespace std;
int n, m, i, j, k, l, r, x, y, v, c[130];
char s[N], t[5], u[N];
void gai(int p, int l, int r, int x, int y){
    if(l == r) c[s[x]] -= m>0, s[x] = y, c[y]++;
    else{
        int m=l+r>>1, lc=p<<1, rc=lc|1;
        if(x <= m) gai(lc, l, m, x, y);
        else gai(rc, m+1, r, x, y);
        u[p] = u[lc] | u[rc] | (s[m]>s[m+1]);
    }//维护区间是否不递减、字母出现次数
}
void cha(int p, int l, int r, int x, int y){
    if(x<=l && r<=y) v |= u[p];
    else{
        int m=l+r>>1, lc=p<<1, rc=lc|1;
        if(x <= m) cha(lc, l, m, x, y);
        if(y > m) cha(rc, m+1, r, x, y);
        if(x<=m && y>m) v |= s[m] > s[m+1];
    }
}
int cnt(char c){
    l = lower_bound(s+x, s+y+1, c) - s;
    r = upper_bound(s+x, s+y+1, c) - s;
    return r - l;//统计[x, y]字符c数量 
}
int main(){
    scanf("%d%s", &n, s+1);
    for(i=1; i<=n; i++) gai(1, 1, n, i, s[i]);
    scanf("%d", &m);
    while(m--){
        scanf("%d%d%s", &k, &x, t);
        if(k == 1) gai(1, 1, n, x, t[0]);
        else{
            sscanf(t, "%d", &y);
            v = 0;
            cha(1, 1, n, x, y);
            if(v) printf("No\n");//出现递减 
            else{//两边不能出现中间字符
                for(i=s[x]+1; i<s[y]; i++){
                    if(cnt(i) < c[i]) break;
                }//中间字符数量要等于总数 
                if(i < s[y]) printf("No\n");
                else printf("Yes\n");
            }
        }
    }
    return 0;
}

作者 crxis

发表回复