考试开始了,可是蒟蒻 HansBug 脑中还是一片空白。哦不!准确的说是乱七八糟的。现在首要任务就是帮蒟蒻 HansBug 理理思维。假设 HansBug 的思维是一长串字符串(字符串中包含且仅包含 个字母),现在的你,有一张神奇的药方,上面依次包含了三种操作:
获取第 到第 个字符中字母 出现了多少次
将第 到第 个字符全部赋值为字母
将第 到第 个字符按照 的顺序排序
你欣喜若狂之时,可是他脑细胞和
RP
已经因为之前过度紧张消耗殆尽,眼看试卷最后还有一篇八百字的作文呢,所以这个关键的任务就交给你啦!
这道题我的做法是线段树,由于只有26个字母,所有我们可以建 个线段树。
对于操作 1
我们维护一下区间和就可以了。
对于操作 2
我们用 就可以了
对于操作 3
我们发现就是操作
1
和操作2
的结合
值得一提的是,有一个剪枝优化能是程序快很多
int query(int num,int l,int r){
if(t[num].sum==0)return 0;//剪枝
if(t[num].l>=l&&t[num].r<=r)return t[num].sum;
pushdown(num);
if(t[ls].r<l)return query(rs,l,r);
if(t[rs].l>r)return query(ls,l,r);
return query(ls,l,r)+query(rs,l,r);
}
void change(int num,int l,int r,int f){
if(t[num].tag==f)return;//剪枝
if(t[num].l>=l&&t[num].r<=r){
dwn(num,f);
return;
}pushdown(num);
if(t[ls].r>=l)change(ls,l,r,f);
if(t[rs].l<=r)change(rs,l,r,f);
pushup(num);
}
这 个剪枝虽然非常显然,但可以使程序快很多
代码:
#include <bits/stdc++.h>
#define ls num<<1
#define rs num<<1|1
using namespace std;
typedef long long ll;
namespace io {//CYjian的快读模板
const int __SIZE = (1 << 21) + 1;
char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55]; int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout), oS = obuf; }
inline void gc (char &x) { x = Gc(); }
inline void pc (char x) { *oS ++ = x; if (oS == oT) flush (); }
inline void pstr (const char *s) { int __len = strlen(s); for (__f = 0; __f < __len; ++__f) pc (s[__f]); }
inline void gstr (char *s) { for(__c = Gc(); __c < 32 || __c > 126 || __c == ' ';) __c = Gc();
for(; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc()) *s = __c; *s = 0; }
template <class I> inline bool gi (I &x) { _eof = 0;
for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc()) { if (__c == '-') __f = -1; _eof |= __c == EOF; }
for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc()) x = x * 10 + (__c & 15), _eof |= __c == EOF; x *= __f; return !_eof; }
template <class I> inline void print (I x) { if (!x) pc ('0'); if (x < 0) pc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) pc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
} using io::pc; using io::gc; using io::pstr; using io::gstr; using io::gi; using io::print;
inline void rech(char &ch){
gc(ch);
for(;!isupper(ch)&&!islower(ch);gc(ch));
}
const int N=1e5+10;
int n,m,F[305];
char a[N];
struct node{
struct Tree{
int l,r,sum,tag,len;
}t[N<<2];
void pushup(int num){
t[num].sum=t[ls].sum+t[rs].sum;
}
void dwn(int num,int f){
t[num].tag=f;
if(t[num].tag==1)t[num].sum=t[num].len;
if(t[num].tag==2)t[num].sum=0;
}
void pushdown(int num){
if(t[num].tag==0)return;
dwn(ls,t[num].tag);
dwn(rs,t[num].tag);
t[num].tag=0;
}
void build(int l,int r,int num,char ch){
t[num].tag=0;
t[num].l=l;t[num].r=r;
t[num].len=r-l+1;
if(l==r){
t[num].sum=a[l]==ch;
return;
}int mid=(l+r)>>1;
build(l,mid,ls,ch);
build(mid+1,r,rs,ch);
pushup(num);
}
int query(int num,int l,int r){
if(t[num].sum==0)return 0;//剪枝
if(t[num].l>=l&&t[num].r<=r)return t[num].sum;
pushdown(num);
if(t[ls].r<l)return query(rs,l,r);
if(t[rs].l>r)return query(ls,l,r);
return query(ls,l,r)+query(rs,l,r);
}
void change(int num,int l,int r,int f){
if(t[num].tag==f)return;//剪枝
if(t[num].l>=l&&t[num].r<=r){
dwn(num,f);
return;
}pushdown(num);
if(t[ls].r>=l)change(ls,l,r,f);
if(t[rs].l<=r)change(rs,l,r,f);
pushup(num);
}
}T[110];
int main(){
gi(n);gi(m);
for(int i=1;i<=n;i++)rech(a[i]),a[i]=toupper(a[i]);
for(char i='A';i<='Z';i++)T[i].build(1,n,1,i);
while(m--){
int f,x,y;char k;
gi(f);gi(x);gi(y);
if(f==1){
rech(k);
k=toupper(k);
print(T[k].query(1,x,y));
pstr("
");
}
if(f==2){
rech(k);
k=toupper(k);
for(char i='A';i<='Z';i++)
if(i==k)T[i].change(1,x,y,1);
else T[i].change(1,x,y,2);
}
if(f==3){
for(char i='A';i<='Z';i++){
F[i]=T[i].query(1,x,y);
T[i].change(1,x,y,2);
}
for(char i='A';i<='Z';i++)
if(F[i])T[i].change(1,x,x+F[i]-1,1),x+=F[i];
}
}
return 0;
}