链接:
https://www.nowcoder.com/acm/contest/112/D
来源:牛客网
来源:牛客网
题目描述
一个只含数字的字符串,q次操作,每次操作将第i位数字改为x,每次操作后,统计长度在[l, r]之间且首数字大于尾数字的子串的个数。
输入描述:
第一行一个只含数字的字符串; 第二行3个整数q, l, r; 接下来q行,每行两个整数i, x。
输出描述:
输出q行,每行一个整数,表示长度在[l, r]之间且首数字大于尾数字的子串的个数。
题解:因为数字只有10个,我们考虑建10个线段树,对于每个线段树,只保存所有区间的相应数字的个数,然后
先预处理出原始的答案,对于每次查询,减去当前位置的贡献,再加上修改后的贡献即可。具体见代码。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
#define maxn 100005
ll ans;
int n,q,a[maxn],sum[maxn*8][12],len;
char s[maxn];
void update(int id,int l,int r,int k,int p,int val)
{
if(l==r)
{
sum[id][p]+=val;
return;
}
int mid=(l+r)/2;
if(k<=mid)
update(id*2,l,mid,k,p,val);
else
update(id*2+1,mid+1,r,k,p,val);
sum[id][p]=sum[id*2][p]+sum[id*2+1][p];
}
ll query(int id,int l,int r,int L,int R,int p)
{
if(L>R || l>r) return 0;
if(l>=L && r<=R)
return sum[id][p];
int mid=(l+r)/2;ll res=0;
if(L<=mid)
res+=query(id*2,l,mid,L,R,p);
if(R>mid)
res+=query(id*2+1,mid+1,r,L,R,p);
return res;
}
int main(void)
{
int l,r,x,y;
scanf("%s",s+1);
len=strlen(s+1);
for(int i=1;i<=len;i++)
a[i]=s[i]-'0';
scanf("%d%d%d",&q,&l,&r);
for(int i=1;i<=len;i++)
update(1,1,len,i,a[i],1);
for(int i=1;i<=len;i++)
for(int j=0;j<a[i];j++)
ans+=query(1,1,len,i+1,min(len,i+r-1),j),ans-=query(1,1,len,i+1,min(len,i+l-2),j);
while(q--)
{
scanf("%d%d",&x,&y);
for(int i=a[x]+1;i<=9;i++)
ans-=query(1,1,len,max(1,x-r+1),x-1,i),ans+=query(1,1,len,max(1,x-l+2),x-1,i);
for(int i=0;i<a[x];i++)
ans-=query(1,1,len,x+1,min(len,x+r-1),i),ans+=query(1,1,len,x+1,min(len,x+l-2),i);
update(1,1,len,x,a[x],-1);
a[x]=y;update(1,1,len,x,a[x],1);
for(int i=a[x]+1;i<=9;i++)
ans+=query(1,1,len,max(1,x-r+1),x-1,i),ans-=query(1,1,len,max(1,x-l+2),x-1,i);
for(int i=0;i<a[x];i++)
ans+=query(1,1,len,x+1,min(len,x+r-1),i),ans-=query(1,1,len,x+1,min(len,x+l-2),i);
printf("%lld\n",ans);
}
return 0;
}