Panda HDU - 4046 (线段树, 单点更新)

Panda

 题目链接:HDU - 4046 

题意:给出一条只由'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;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值