CF610E 分块题解
NewMarchqwq · · 题解
这是一个分块题解,时间洛谷前十(不劣于线段树解法),空间是线段树解法的千分之一。好像薄纱除了 ODT 以外所有的解法。(振臂高呼:卡掉 ODT!空间开到 1M!)
1. 如何计数?
考虑如果给定的排列就是
方法很简单:扫一遍
为什么能这样?我们可以把字母看成一个折线图。最后应该是每组
故我们数出断点的个数就是上面的“答案”。显然断点加一就是段数(比如一根木棒切
2. 如何维护?
我们已经有了个
上面的算法是个静态算法,复杂度
考虑如何支持区间修改。我们可以维护
发现 500M 的内存卡的好紧(线段树的空间复杂度为
考虑分块。定义
时间复杂度为
空间复杂度为
3. 如何实现?
说着简单,实现真的非常困难!
首先,我们应该明确块与块之间的关系。比如
还有一个事情是也需要更新
代码:
constexpr int B=1500;
int n,q,k,cnt[14][14],val[140][14][14],id[14];
char s[200010],tag[20010];
inline int bel(int x){return (x-1)/B+1;}
inline int L(int x){return (x-1)*B+1;}
inline int R(int x){return x*B;}
void totL(int i,char c){
if (i!=1){
--val[bel(i-1)][s[i-1]^96][s[i]^96];
--cnt[s[i-1]^96][s[i]^96];
++val[bel(i-1)][s[i-1]^96][c^96];
++cnt[s[i-1]^96][c^96];
}
}
void chgf(int i){
if (i!=n){
--val[bel(i)][s[i]^96][s[i+1]^96];
--cnt[s[i]^96][s[i+1]^96];
}
}
void chg(int i){
// cout<<s[i]<<' '<<c<<' '<<cnt[1][2]<<'\n';
if (i!=n){
++val[bel(i)][s[i]^96][s[i+1]^96];
++cnt[s[i]^96][s[i+1]^96];
}
}
void down(int id){
rep(i,L(id),R(id))s[i]=tag[id];
tag[id]=0;
}
void chk(int id){
if (id>0&&id<=bel(n)-1&&tag[id])down(id);
}
void chkx(int p){
chk(bel(p-1));
chk(bel(p));
chk(bel(p+1));
}
void bfdel(int l,int r){
// cout<<l<<' '<<r<<' '<<c<<'\n';
chkx(l),chkx(r);
// cout<<cnt[1][1]<<'\n';
rep(i,l,r)chgf(i);
}
void bfadd(int l,int r){
// cout<<l<<' '<<r<<' '<<c<<'\n';
chkx(l),chkx(r);
// cout<<cnt[1][1]<<'\n';
rep(i,l,r)chg(i);
}
void add(int l,int r,char c){
// cout<<cnt[2][2]<<'\n';
if (bel(l)+1>=bel(r)){
chkx(l);
totL(l,c);
bfdel(l,r);
rep(i,l,r)s[i]=c;
bfadd(l,r);
return ;
}
// cout<<cnt[1][1]<<'\n';
chkx(l);
totL(l,c);
bfdel(l,R(bel(l)));
bfdel(L(bel(r)),r);
rep(i,bel(l)+1,bel(r)-1){
tag[i]=c;
rep(c1,1,10)rep(c2,1,10){
cnt[c1][c2]-=val[i][c1][c2];
val[i][c1][c2]=0;
}
val[i][c^96][c^96]=R(i)-L(i)+1;
cnt[c^96][c^96]+=val[i][c^96][c^96];
// cout<<val[i][2][2]<<'\n';
// cout<<val[i][2][2]<<'\n';
// cout<<i<<' '<<cnt[c^96][c^96]<<'\n';
}
// cout<<cnt[1][1]<<'\n';
rep(i,l,R(bel(l)))s[i]=c;
rep(i,L(bel(r)),r)s[i]=c;
bfadd(l,R(bel(l)));
bfadd(L(bel(r)),r);
}
int main() {
scanf("%d%d%d%s",&n,&q,&k,s+1);
rep(i,1,n-1)++cnt[s[i]^96][s[i+1]^96];
// cout<<cnt[1][2]<<'\n';
rep(i,1,n-1)++val[bel(i)][s[i]^96][s[i+1]^96];
while (q--){
int o;
scanf("%d",&o);
if (o==1){
int l,r;
char u[2],c;
scanf("%d%d%s",&l,&r,u);
c=u[0];
add(l,r,c);
}else{
char u[15];
scanf("%s",u+1);
int res=1;
// rep(i,1,k)rep(j,1,k)
// cout<<cnt[i][j]<<" \n"[j==k];
rep(i,1,k)id[u[i]^96]=i;
rep(i,1,k)rep(j,1,k)if (id[i]>=id[j])
res+=cnt[i][j];
printf("%d\n",res);
}
}
return 0;
}