这题是网络赛的题目,当时还是菜鸟,所以做不出来!
这题有两种方法做:
第一种是树状数组:效率最高了171ms
#include<cstdio>
#include<cstring>
int c[50002];
int n;
struct node
{
char ch1;
char ch2;
char ch3;
bool flag;
}map[50002];
int lowbit(int t)
{
return t&-t;
}
void plus(int i,int num)
{
while(i<=n)
{
c[i]+=num;
i+=lowbit(i);
}
}
int sum(int i)
{
int sum=0;
while(i>0)
{
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
int t,q,i,j,op,x,y;
char ch1,ch;
char str[50002];
scanf("%d",&t);
for(i=1;i<=t;i++)
{
memset(c,0,sizeof(c));
scanf("%d%d",&n,&q);
scanf("%s",str);
int len=strlen(str);
int p=1;
n=n-2;
for(j=0;j<len-2;j++)
{
map[p].ch1=str[j];
map[p].ch2=str[j+1];
map[p].ch3=str[j+2];
map[p].flag=0;
if(str[j]=='w'&&str[j+1]=='b'&&str[j+2]=='w')
{
//printf("..%d\n",p);
map[p].flag=1;
plus(p,1);
}
p++;
}
printf("Case %d:\n",i);
while(q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%c%c",&x,&ch1,&ch);
getchar();
if(str[x]==ch)
{
continue;
}
str[x]=ch;
x++;
if(x-2>0&&x-2<=n)
{
map[x-2].ch3=ch;
if(map[x-2].flag)
{
plus(x-2,-1);
map[x-2].flag=0;
}
else
{
if(map[x-2].ch1=='w'&&map[x-2].ch2=='b'&&map[x-2].ch3=='w')
{
plus(x-2,1);
map[x-2].flag=1;
}
}
}
if(x-1>0&&x-1<=n)
{
map[x-1].ch2=ch;
if(map[x-1].flag)
{
plus(x-1,-1);
map[x-1].flag=0;
}
else
{
if(map[x-1].ch1=='w'&&map[x-1].ch2=='b'&&map[x-1].ch3=='w')
{
plus(x-1,1);
map[x-1].flag=1;
}
}
}
if(x<=n)
{
map[x].ch1=ch;
if(map[x].flag)
{
plus(x,-1);
map[x].flag=0;
}
else
{
if(map[x].ch1=='w'&&map[x].ch2=='b'&&map[x].ch3=='w')
{
plus(x,1);
map[x].flag=1;
}
}
}
}
else
{
scanf("%d%d",&x,&y);
if(y<x+2)
{
printf("0\n");
continue;
}
if(x>n)
{
x=n;
}
if(y>n)
{
y=n;
}
else
{
if(y==2)
{
y=1;
}
else
{
y=y-1;
}
}
int ans1=sum(x);
int ans2=sum(y);
printf("%d\n",ans2-ans1);
}
}
}
return 0;
}
第二种是线段树:250ms
#include<stdio.h>
#include<string.h>
#define N 50005
struct node
{
int l,r;
int num;
}tree[N*4];
int flag[N];
int ans;
void build(int s,int l,int r)
{
tree[s].l=l;
tree[s].r=r;
tree[s].num=0;
if(l==r)
{
if(flag[l]==1)
tree[s].num=1;
return ;
}
int mid=(l+r)>>1;
build(s<<1,l,mid);
build(s<<1|1,mid+1,r);
tree[s].num+=tree[s<<1].num+tree[s<<1|1].num;
}
void updata(int s,int k,int sum)
{
tree[s].num+=sum;
if(tree[s].l==tree[s].r)
return ;
int mid=(tree[s].l+tree[s].r)>>1;
if(k<=mid)
{
updata(s<<1,k,sum);
}
else
{
updata(s<<1|1,k,sum);
}
}
void compute(int s,int x,int y)
{
if(tree[s].l==x&&tree[s].r==y)
{
ans+=tree[s].num;
return ;
}
int mid=(tree[s].l+tree[s].r)>>1;
if(y<=mid)
{
compute(s<<1,x,y);
}
else
{
if(x>mid)
{
compute(s<<1|1,x,y);
}
else
{
compute(s<<1,x,mid);
compute(s<<1|1,mid+1,y);
}
}
}
int main()
{
int t,n,q,i,k,p,x,y,flag1;
int text=1;
char str[N];
char ch,ch1,ch2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&q);
memset(flag,0,sizeof(flag));
scanf("%s",str+1);
printf("Case %d:\n",text++);
for(i=1;i<=n-2;i++)
{
if(str[i]=='w'&&str[i+1]=='b'&&str[i+2]=='w')
{
flag[i]=1;
}
}
if(n-2<=0)
{
flag1=1;
}
else
{
build(1,1,n-2);
flag1=0;
}
while(q--)
{
scanf("%d",&k);
if(k==1)
{
scanf("%d%c%c%c",&p,&ch,&ch1,&ch2);
p++;
if(str[p]==ch1)
continue;
int sum=0;
if(str[p-2]=='w'&&str[p-1]=='b'&&str[p]=='w')
{
sum=-1;
}
if(str[p-2]=='w'&&str[p-1]=='b'&&ch1=='w')
{
sum=1;
}
if(sum!=0)
updata(1,p-2,sum);
sum=0;
if(str[p-1]=='w'&&str[p]=='b'&&str[p+1]=='w')
{
sum=-1;
}
if(str[p-1]=='w'&&ch1=='b'&&str[p+1]=='w')
{
sum=1;
}
if(sum!=0)
updata(1,p-1,sum);
sum=0;
if(str[p]=='w'&&str[p+1]=='b'&&str[p+2]=='w')
{
sum=-1;
}
if(ch1=='w'&&str[p+1]=='b'&&str[p+2]=='w')
{
sum=1;
}
if(sum!=0)
updata(1,p,sum);
str[p]=ch1;
}
else
{
scanf("%d%d",&x,&y);
x++;
y++;
ans=0;
if(x+2<=y&&flag1==0)
{
y=y-2;
compute(1,x,y);
}
printf("%d\n",ans);
}
}
}
return 0;
}
这两种都有各自的优缺点,能用树状数组做的,就可以用线段树做,嘿嘿!