题目大意:在一串字符串中某个区间查询wbw的数目,更新某个位置的字符
思路:线段树,每个枝结点记录以这个点为中心的字符是不是wbw,所以每次某个位置更新的时候,左右两个位置均要更新
而且查询的时候某个区间的wbw的个数,位于边界的字符的值不能算在内
//561MS 3400K 3373 B #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define RR(x) (x<<1|1) #define LL(x) (x<<1) const int M =50000+5000; int n,m; char str[M]; int rts[M];//每个字符位置对应线段树根结点的位置 struct node { int l,r; int sum; int mid() { return (l+r)>>1; } }; inline bool ok(int pos) { return (str[pos]=='b'&&str[pos-1]=='w'&&str[pos+1]=='w'); } struct Segtree { node tree[M<<2]; void up(int rt) { tree[rt].sum=tree[LL(rt)].sum+tree[RR(rt)].sum; } void build(int l,int r,int rt) { tree[rt].l = l; tree[rt].r = r; if(l==r) { rts[l]=rt; if(l==0||l==n-1) tree[rt].sum=0; else tree[rt].sum = ok(l); return ; } int mid=tree[rt].mid(); build(l,mid,LL(rt)); build(mid+1,r,RR(rt)); up(rt); } void update(int pos,char ch,int rt) { if(tree[rt].l==tree[rt].r) { str[pos]=ch; if(pos==0||pos==n-1) tree[rt].sum=0; else tree[rt].sum= ok(pos); return ; } int mid=tree[rt].mid(); if(pos<=mid) update(pos,ch,LL(rt)); else update(pos,ch,RR(rt)); up(rt); } int query(int L,int R,int rt) { if(L<=tree[rt].l&&tree[rt].r<=R) { int tmp=0; if(L==tree[rt].l&&tree[rts[L]].sum) tmp++; if(R==tree[rt].r&&tree[rts[R]].sum) tmp++; if(L==R) tmp=tree[ rts[R] ].sum ; return tree[rt].sum-tmp; } int sum=0; int mid=tree[rt].mid(); if(L<=mid) sum+=query(L,R,LL(rt)); if(R>mid) sum+=query(L,R,RR(rt)); return sum; } }seg; int main() { int T; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { printf("Case %d:\n",cas); scanf("%d%d",&n,&m); scanf("%s",str); seg.build(0,n-1,1); while(m--) { int op; scanf("%d",&op); if(op==0) { int l,r; scanf("%d%d",&l,&r); printf("%d\n",seg.query(l,r,1)); } else { int p; char ch; scanf("%d %c",&p,&ch); seg.update(p,ch,1); if(p-1>0) seg.update(p-1,str[p-1],1); if(p+1<n-1) seg.update(p+1,str[p+1],1); } } } return 0; }
时间: 2024-10-28 19:43:11