题意是50个测试用例,每次输入一个大小为10万int型的序列,附带有10万个操作,操作分为改动元素值和询问
赋值的格式是 S A B,意思是a【A】=B
询问的格式Q L R D P,意思是从a【L】到a【R】区间所有整数第D位为P的元素个数 比如区间是
。。。11 12 13.。。。那么D=2 P=1就表示第二位(十位)是1的元素个数,结果为3
int型数据最多D=10位,每位只有P=0-9这几个数,所以询问的位置可能出现D*P=10*10=100种情况
维护10*10个树状数组,每个树状数组拥有10万个元素,数组太大,内存超出。
有一种编程技巧是离线处理树状数组的询问赋值,而不是随着用户输入实时计算结果。
简言之就是降低一个维度,10*10个树状数组变成10个
而外层加个for循环用时间换空间
赋值的格式是 S A B,意思是a【A】=B
询问的格式Q L R D P,意思是从a【L】到a【R】区间所有整数第D位为P的元素个数 比如区间是
。。。11 12 13.。。。那么D=2 P=1就表示第二位(十位)是1的元素个数,结果为3
int型数据最多D=10位,每位只有P=0-9这几个数,所以询问的位置可能出现D*P=10*10=100种情况
维护10*10个树状数组,每个树状数组拥有10万个元素,数组太大,内存超出。
有一种编程技巧是离线处理树状数组的询问赋值,而不是随着用户输入实时计算结果。
简言之就是降低一个维度,10*10个树状数组变成10个
而外层加个for循环用时间换空间
询问操作是getsum(r,position)-getsum(l,position)
赋值操作不仅要update树状数组的某一位加一,还要update这一位之前的数值减一,所以每次赋值后还要记录下这次赋值的数据,下次很可能把这位赋值成其他数值,那么这次update加一操作还要减回去
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAX 100005
int f[MAX][10];
int a[MAX];//保存n个输入
int n,m;
int pre[MAX];
struct enque//保存询问
{
char c;
int x,y;
int l,r,d,p;
int ans;
}enq[MAX];
int lowbit(int t) {return t&(-t);}
int getsum(int a[][10],int t,int pos){//查询1~t区间当前位上为pos的总数
int sum=0;
while(t>0){
sum=sum+a[t][pos];
t=t-lowbit(t);
}
return sum;
}
void Insert(int a[][10],int t,int d,int m,int pos){//t~m区间当前位为pos的位置+d
while(t<=m){
a[t][pos]=a[t][pos]+d;
t+=lowbit(t);
}
}
int main()
{
int t,x;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
cin>>enq[i].c;
if(enq[i].c=='Q') scanf("%d%d%d%d",&enq[i].l,&enq[i].r,&enq[i].d,&enq[i].p);
else scanf("%d%d",&enq[i].x,&enq[i].y);
}
int p=1;
for(int i=1;i<=10;i++)//从1~10位循环循环解决询问
{
memset(f,0,sizeof(f));
for(int j=1;j<=n;j++)
{
Insert(f,j,1,n,(a[j]/p)%10);
pre[j]=(a[j]/p)%10;
}
for(int k=1;k<=m;k++)
{
if(enq[k].c=='Q'&&enq[k].d==i){
enq[k].ans=getsum(f,enq[k].r,enq[k].p)-getsum(f,enq[k].l-1,enq[k].p);
}
else if(enq[k].c=='S'){
int s=(enq[k].y/p)%10;
if(s!=pre[enq[k].x]) {
Insert(f,enq[k].x,-1,n,pre[enq[k].x]);
Insert(f,enq[k].x,1,n,s);
pre[enq[k].x]=s;//pre数组记录当前位的数字,S修改时先减去之前的
}
}
}
p*=10;
}
for(int i=1;i<=m;i++)
if(enq[i].c=='Q') printf("%d\n",enq[i].ans);
}
return 0;
}