HDU5057 Argestes and Sequence(分块题解)

        这道题是比较经典的分块中,单点修改+区间查询的应用

遇见区间问题,我们先想到的是高级数据结构,如树状数组,线段树等,(当然这道题也是一道训练树状数组的好题,只不过编码难度比较高,需要关注空间优化 ,降维),,而分块编码比较简单,需要我们分析复杂度,另外此题的位数查询中有个小trick,少了会TLE.

#include <iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define endl '\n'
const int N = 1e5 + 10;
const int B = 320;
int n,m,blen,bnum;
int a[N], bi[N], bl[B], br[B];
int pow10v[12];
int block[B][11][11];//表示第i块中的每个数的第d位是p的总个数
void build(){
    blen=sqrt(n);
    bnum=(n+blen-1)/blen;
    for(int i=1;i<=n;i++){
        bi[i] = (i - 1) / blen + 1;
    }
    for(int i=1;i<=bnum;i++){
        bl[i] = (i - 1) * blen + 1;
        br[i] = min(n, i * blen);
    }
    //处理block数组
    for(int i=1;i<=bnum;i++){
        for(int j=bl[i];j<=br[i];j++){
            int cur=a[j];
            int num = 1;
            while(num<=10){
                int low = cur % 10;
                block[i][num][low]++;
                cur /= 10;
                num++;
            }
        }
    }
}
inline int get_digit(int d,int val){
    return val / pow10v[d] % 10;
}
void update(int x,int y){
    int old_num = a[x];
    a[x]=y;
    int no=bi[x];

    int num = 1;
    while(num<=10){
        int low=old_num%10;
        block[no][num][low]--;
        old_num/=10;
        num++;
    }
    num=1;
    int cur=y;
    while(num<=10){
        int low=cur%10;
        block[no][num][low]++;
        cur/=10;
        num++;
    }
}
long long query(int l,int r,int d,int p){
    long long res=0;
    if(bi[l]==bi[r]){
        //在同一块
        for(int i=l;i<=r;i++){
            int cur=a[i];
            if(get_digit(d,cur)==p){
                res++;
            }
        }
    }else{
        for(int i=l;i<=br[bi[l]];i++){
            int cur=a[i];
            if(get_digit(d,cur)==p)
                res++;
        }
        for (int i = bl[bi[r]]; i <= r; i++)
        {
            int cur = a[i];
            if(get_digit(d,cur)==p)res++;
        }
        //处理整块
        for(int i=bi[l]+1;i<=bi[r]-1;i++){
            res += block[i][d][p];
        }
    }
    return res;
}
void solved(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    build();
    char op;
    int x,y,l,r,d,p;
    for(int i=1;i<=m;i++){
        cin>>op;
        if(op=='S'){
            cin>>x>>y;
            update(x, y);
        }else{
            cin>>l>>r>>d>>p;
            cout<<query(l,r,d,p)<<endl;
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int T=1;
    cin>>T;
    pow10v[1] = 1;
    for (int i = 2;i<=10;i++){
        pow10v[i] = pow10v[i - 1] * 10;
    }
    while (T--)
    {
        memset(block, 0, sizeof(block));
        solved();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值