Panda
题意:给出一条只由'b', 'w'字符组成的字符串,两种操作:
0 L R:查询区间[L, R]中有多少个子串是"wbw"组合;
1 x ch:将x位置的字符改为ch;
思路:一看这个题就是妥妥的线段树;但是首先怎么存区间[L, R]中"wbw"的个数呢?
"wbw"是三个字符,把三个字符存到同一节点?显然不行,因为如果这样的话L, L+1, L+2, L+3岂不是要存两次?查询区间怎么办?
所以我们可以这样:每遇到"wbw"就将第三个位置标记为1,这样查出来的a[x]表示x-2, x-1, x是否是"wbw";所以查询区间[L, R]时,实则是查询[L+2, R];
查询解决了,再来看看更新;此处的更新是前一发而动三点;

如上图修改5位置影响的是绿蓝紫三个区间段,对于任意一个区间段如果之前是"wbw"第三个位置就要改为0,如果之前不是"wbw",修改之后是了,第三个位置就要改为1;
#include <bits/stdc++.h>
using namespace std;
const int maxn=50010;
char letter[maxn];
struct node{
int sum, l, r;
}tr[maxn<<2];
void pushup(int m){
tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
}
bool ok(int i, int j, int k){
if(letter[i]=='w'&&letter[j]=='b'&&letter[k]=='w') return true;
return false;
}
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
if(l==r){
if(l<=2) tr[m].sum=0;
else tr[m].sum=ok(l-2, l-1, l)?1:0;
return;
}
int mid=(l+r)>>1;
build(m<<1, l, mid);
build(m<<1|1, mid+1, r);
pushup(m);
}
void updata(int m, int inx, int val){
if(tr[m].l==tr[m].r){
tr[m].sum=val;
return;
}
int mid=(tr[m].l+tr[m].r)>>1;
if(inx<=mid) updata(m<<1, inx, val);
else updata(m<<1|1, inx, val);
pushup(m);
}
int query(int m, int l, int r){
if(tr[m].l==l&&tr[m].r==r){
return tr[m].sum;
}
int mid=(tr[m].l+tr[m].r)>>1;
int temp;
if(r<=mid) temp=query(m<<1, l, r);
else if(l>mid) temp=query(m<<1|1, l, r);
else{
temp=query(m<<1, l, mid)+query(m<<1|1, mid+1, r);
}
return temp;
}
int main(){
int T, cas=0;
scanf("%d", &T);
while(T--){
int n, m;
scanf("%d%d", &n, &m);
scanf("%s", letter+1);
build(1, 1, n);
printf("Case %d:\n", ++cas);
while(m--){
int k;
scanf("%d", &k);
if(k==0){
int l, r;
scanf("%d%d", &l, &r);
l++, r++;
if(r-l>=2)//如果询问区间小于3就直接输出零;
printf("%d\n", query(1, l+2, r));
else printf("0\n");
}
else{
int x;
char ch[2];
scanf("%d %s", &x, ch);
x++;
if(ch[0]==letter[x]) continue;
if(x>=3){
if(ok(x-2, x-1, x)) updata(1, x, 0);
if(letter[x-2]=='w'&&letter[x-1]=='b'&&letter[x]=='b') updata(1, x, 1);
}
if(x>=2&&x<n){
if(ok(x-1, x, x+1)) updata(1, x+1, 0);
if(letter[x-1]=='w'&&letter[x]=='w'&&letter[x+1]=='w') updata(1, x+1, 1);
}
if(x<n-1){
if(ok(x, x+1, x+2)) updata(1, x+2, 0);
if(letter[x]=='b'&&letter[x+1]=='b'&&letter[x+2]=='w') updata(1, x+2, 1);
}
letter[x]=ch[0];
}
}
}
return 0;
}
本文介绍了一种使用线段树解决特定字符组合wbw的查询和更新问题的方法。通过巧妙地将wbw的检测转化为单一位置的标记,实现了高效查询区间内wbw组合的数量,同时处理字符串更新操作。
1407

被折叠的 条评论
为什么被折叠?



