hdu5057  树状数组

本文介绍了一种解决区间数字统计问题的高效算法。通过使用线段树和树状数组的优化思路,结合标记策略减少内存消耗,实现了在限定空间内快速查询特定区间内某位数上特定数字出现次数的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出一个序列 然后操作是询问在某一个区间中某一位上的某一个数字的个数

或者是修改其中的某一个数字

解法:这题一上来自然就敲了一个线段树 然而空间要4000w 不用交就知道mle啊 

然后想到树状数组那也就1000w 但是这个也是太大了 

有另外一种做法 就是拿时间来换空间 离线所有询问 然后对于每一位的询问分别进行询问 那么询问就变成100w了

这个线段树估计是被卡常数了 然后树状数组把挂全部加上 rp好的话或许卡过 

这里采用的做法是进行标记 就像刚开始写大数假发一样 进行标记 考虑到unsigned short可以在空间上满足1000w的要求 再加上一个bool标记 基本上就可以在空间限制范围内了 其余的应该都会吧

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int _,t,n,m,a[100010],x,y;
char op[5];
unsigned short sum[100001][10][10];
bool fl[100001][10][10];
int scan(){
    int res;char ch;bool neg;
    while(ch=getchar(),!isdigit(ch)&&ch!='-');
    if(ch=='-'){
        res=0;
        neg=true;
    }else{
        res = ch - '0';
        neg = false;
    }
    while (ch = getchar(), isdigit(ch))
        res=res*10+ch-'0';
    return neg ? -res : res;
}
inline void add(int q,int w,int x,int y){
    for(;x<=n;x+=x&-x){
        if(y==1){
            if(sum[x][q][w]==65535)sum[x][q][w]=0,fl[x][q][w]=1;
            else sum[x][q][w]++;
        }else{
            if(sum[x][q][w]==0)sum[q][w][x]=65535,fl[x][q][w]=0;
            else sum[x][q][w]--;
        }
    }
}
inline int _sum(int q,int w,int x){
    int t=0;
    for(;x;x-=x&-x)t+=sum[x][q][w]+(fl[x][q][w]?65536:0);
    return t;
}
int main(){
  scanf("%d",&_);
  while(_--){
    n=scan();m=scan();
    for(int i=0;i<10;++i)
        for(int j=0;j<10;++j)
            for(int k=1;k<=n;++k)
                sum[k][i][j]=fl[k][i][j]=0;

    for(int i=1;i<=n;i++){
        a[i]=scan();
        for(int t=a[i],j=0;j<10;t/=10,j++)add(j,t%10,i,1);
    }
    while(m--){
        scanf("%s",op);
        if(op[0]=='S'){
            x=scan();y=scan();
            for(int t=a[x],j=0;j<10;t/=10,j++)
                add(j,t%10,x,-1);
            a[x]=y;
            for(int t=a[x],j=0;j<10;t/=10,j++)
                add(j,t%10,x,1);
        }else{
            x=scan();y=scan();int i=scan();int j=scan();i--;
            int __sum=_sum(i,j,y)-_sum(i,j,x-1);
            printf("%d\n",__sum);
            
        }
    }
  }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值