题干:
给你n个数a[i],和m组询问。询问包括两种格式add l,r,val和count l,r:
add表示将区间[l,r]的数都加上val;
count表示查询区间[l,r]的数中有多少幸运数字(幸运数字仅由4 米斯达点了个? 和7组成
(如:4,7,47,4477;147则不是))
思路:
区间修改,区间查询,一般就是线段树或者树状数组了。
然后就是要明确维护的值是什么值,首先要维护区间内幸运数字的个数,然后因为要高效的求出修改后的值,所以需要维护区间内的数到幸运数字的距离的最小值及个数,然后每次更新完数据后要根据标记稍微重建一下树。
详细操作见代码…
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int mx =110000;
int luck[32]={4,7,44,47,74,77,444,447,474,477,744,747,774,777,4444,4447,4474,4477,
4744,4747,4774,4777,7444,7447,7474,7477,7744,7747,7774,7777,44444,44447}; //幸运数字数组
ll dis[11000],a[mx];
struct stu
{
int l,r;
int x,y,lazy;
}tree[4*mx];
void pushup(int x) //更新数组的区间值
{
int t1=x<<1,t2=(x<<1)+1;
if(tree[t1].x==tree[t2].x){
tree[x].x=tree[t1].x;
tree[x].y=tree[t1].y+tree[t2].y;
}
else if(tree[t1].x>tree[t2].x){
tree[x].x=tree[t2].x;
tree[x].y=tree[t2].y;
}
else{
tree[x].x=tree[t1].x;
tree[x].y=tree[t1].y;
}
}
void build(int x,int l,int r)
{
tree[x].l=l;
tree[x].r=r;
tree[x].lazy=0;
if(l==r){
tree[x].x=dis[a[l]];
tree[x].y=1;
return;
}
int m=(l+r)>>1;
build(x<<1,l,m);
build((x<<1)+1,m+1,r);
pushup(x);
}
void pushdown(int x)
{
if(tree[x].lazy) //懒标记下放
{
int t1=x<<1,t2=(x<<1)+1;
tree[t1].lazy+=tree[x].lazy;
tree[t2].lazy+=tree[x].lazy;
tree[t1].x+=tree[x].lazy;
tree[t2].x+=tree[x].lazy;
tree[x].lazy=0;
}
}
void updata(int x,int l,int r,int val)
{
if(l<=tree[x].l&&tree[x].r<=r)
{
tree[x].x+=val;
tree[x].lazy+=val;
return;
}
pushdown(x);
int m=(tree[x].l+tree[x].r)>>1;
if(m>=r) updata(x<<1,l,r,val);
else if(l>m) updata(x<<1|1,l,r,val);
else
{
updata(x<<1,l,m,val);
updata(x<<1|1,m+1,r,val);
}
pushup(x);
}
int que(int x,int l,int r)
{
if(tree[x].x) return 0;
if(l<=tree[x].l&&tree[x].r<=r)
return tree[x].y;
pushdown(x);
int m=(tree[x].l+tree[x].r)>>1;
if(m>=r) return que(x<<1,l,r);
if(l>m) return que(x<<1|1,l,r);
return que(x<<1,l,m)+que(x<<1|1,m+1,r);
}
void rebuild(int x)
{
if(tree[x].x>=0) return; //如果距离为正则不用更新
if(tree[x].l==tree[x].r){
a[tree[x].l]-=tree[x].lazy; //更新根的值
tree[x].x=dis[a[tree[x].l]]; //得到新的距离
tree[x].lazy=0;
return;
}
pushdown(x);
rebuild(x<<1);
rebuild((x<<1)+1);
pushup(x);
}
int main()
{
int n,m,now=0,x,y,z;
char ch[10];
scanf("%d%d",&n,&m);
for(int i=1;i<=10000;i++){
if(i>luck[now]) now++;
dis[i]=luck[now]-i;
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
for(int i=0;i<m;i++){
scanf("%s",ch);
if(ch[0]=='a'){
scanf("%d%d%d",&x,&y,&z);
updata(1,x,y,-z); //因为是加法所以距离变小
rebuild(1); //从头开始遍历是否要重建树
}
else if(ch[0]=='c'){
scanf("%d%d",&x,&y);
printf("%d\n",que(1,x,y));
}
}
return 0;
}