jzoj4243 【五校联考6day1】c 分块

16 篇文章 0 订阅

Description


定义S 为十进制只由4 和7 组成的全体正整数的集合。
对于1 ≤ i ≤ N,给定ai。要求完成M 个操作:
add l r v 将i ∈ [l, r] 的所有ai 加上v
count l r 统计有多少i 满足i ∈ [l, r] 且 ai ∈ S

Data Constraint


50% 的数据满足N,M ≤ 103
 100% 的数据满足1 ≤ N,M ≤ 105; 1 ≤ ai ≤ 104; 1 ≤ v ≤ 104
 数据保证所有操作结束后ai ≤ 104。

Solution


本蒟蒻第一题手写的分块,感慨一下
把序列分成 n 个块并维护每个块的桶。
对于一段(l,r)查询,暴力修改两端,中间的块就打标记
对于一段(l,r,v)修改,暴力修改两端,中间的块打标记
表示平衡树太jb难调了于是滚过来写点别的

Code


#include <stdio.h>
#include <string.h>
#include <math.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define N 200005
#define M 20005
int rec[N],pos[N],add[N],a[N],s[N],e[N],t[501][M];
int n,m;
void read(int &x) {
    x=0; int v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    x*=v;
}
void update(int x,int &y,int w) {
    --t[x][y]; y+=w; ++t[x][y];
}
void prework() {
    int st=1; rec[0]=0;
    rec[++rec[0]]=4;
    rec[++rec[0]]=7;
    while (st<=rec[0]) {
        int now=rec[st++];
        if (now*10>=M) return;
        rec[++rec[0]]=now*10+4;
        rec[++rec[0]]=now*10+7;
    }
}
void modify(int l,int r,int v) {
    if (pos[l]==pos[r]) {
        rep(i,l,r) update(pos[l],a[i],v);
    } else {
        rep(i,s[pos[r]],r) update(pos[r],a[i],v);
        rep(i,l,e[pos[l]]) update(pos[l],a[i],v);
        rep(i,pos[l]+1,pos[r]-1) add[i]+=v;
    }
}
int query(int l,int r) {
    int ret=0;
    if (pos[l]==pos[r]) {
        rep(i,l,r) {
            rep(j,1,rec[0]) ret+=(a[i]+add[pos[l]])==rec[j];
        }
    } else {
        rep(i,s[pos[r]],r) {
            rep(j,1,rec[0]) ret+=(a[i]+add[pos[r]])==rec[j];
        }
        rep(i,l,e[pos[l]]) {
            rep(j,1,rec[0]) ret+=(a[i]+add[pos[l]])==rec[j];
        }
        rep(i,pos[l]+1,pos[r]-1) {
            rep(j,1,rec[0]) ret+=t[i][rec[j]-add[i]];
        }
    }
    return ret;
}
int main(void) {
    prework();
    read(n); read(m);
    int size=(int)(sqrt(n));
    rep(i,1,n) {
        read(a[i]);
        pos[i]=(i-1)/size+1;
        if (!s[pos[i]]) s[pos[i]]=i;
        e[pos[i]]=i;
        ++t[pos[i]][a[i]];
    }
    while (m--) {
        char opt[5];
        int l,r,v;
        scanf("%s",opt);
        if (opt[0]=='c') {
            read(l); read(r);
            printf("%d\n",query(l,r));
        } else {
            read(l); read(r); read(v);
            modify(l,r,v);
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值