思路:
Hint 1
由于该题内存限制,如果使用保存每一位上的特定的数有多少个的树状数组,即
tree[n][digit][number] n : 数的下标 digit : 第几位 number : 该digit位上的数是几
。这样会超出内存限制的
这是一个三维的数组,有没有办法减少一维呢?如果减少,哪一维是可能减少的呢?
Hint 2
去掉digit那一维,用 tree[n][number] 来储存信息即可
因为省去了digit那一维度,不妨遍历1-10位,当遍历到第i位时,用tree保存当前数位等于number的数有多少即可
Hint 3
在处理第i位时,首先将未经任何修改的原数组中的数所对应位的信息更新到tree上保存,
在接下来的 1-m ,共m个操作中,询问和修改是穿插的,询问中,有一些不是问第i位信息的,真的有必要一个一个判断某个询问是否在问第i位吗?可不可以在读入询问和操作的时候,将询问第i位的询问下标(下标指的是1-m中的某数)记录下来,待处理该位时直接根据索引,调出这些询问的下标是多少呢?
Hint 4
在处理第i位时,现在虽然可以直接定位,那些针对第i位的询问,可是中途穿插的修改怎么实现呢,难道真的需要遍历该询问前的所有操作,看看哪些是修改操作,然后再进行修改吗?
Hint 5
将下标为x的询问前,进行的修改的次数,记录下来。具体来说,当遍历到1-m个操作中的某一个下标为x的操作时,若发现该操作是修改,那么将记录修改次数的数组optimes[i](表示i号操作前有多少次修改)的值加1,i从x+1 取到 m,有什么办法加快这一进程吗?是的,再用树状树组
Hint 6
只需修改的次数,就能完成对应修改,是不是将修改依次保存在一个数组中就可以了呢?其中,数组的下标表示这个第几次修改
Solution
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define lowbit(x) (x&(-x))
const int maxn=100005,maxm=maxn;
int n,m;
int tree[2][maxn][10],a[maxn],b[maxn],optimes[maxm];
//tree[0] : times that the number on a specific digit appear
//tree[1] : count of changes before act i
vector<int> qidx[15];
struct query{
int l,r,p,ans=-1;
}q[maxm];
struct revise{
int x,y;
};
vector<revise> op;
void update(int t,int x,int p,int d1)
{
while(x<=maxn)
{
tree[t][x][p]+=d1;
x+=lowbit(x);
}
}
int sum(int t,int x,int p)
{
int res=0;
while(x>0)
{
res+=tree[t][x][p];
x-=lowbit(x);
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
memset(tree,0,sizeof(tree));
op.clear();
for(int i=1;i<=10;i++)
qidx[i].clear();
for(int i=1;i<=m;i++)
q[i].ans=-1;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=m;i++)
{
char o;
cin>>o;
if(o=='S')
{
revise rv;
cin>>rv.x>>rv.y;
update(1,i,0,1);
op.push_back(rv);
}
else
{
int d;
cin>>q[i].l>>q[i].r>>d>>q[i].p;
qidx[d].push_back(i);
}
}
for(int i=1;i<=m;i++)
{
optimes[i]=sum(1,i,0);
//printf("optimes[%d]=%d\n",i,optimes[i]);
}
//printf("##%d\n",optimes[7]);
//process
long long div[12]={0,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
for(int dig=1;dig<=10;dig++)
{
for(int i=1;i<=n;i++)
for(int j=0;j<=9;j++)
tree[0][i][j]=0;
for(int i=1;i<=n;i++)
b[i]=a[i];
for(int i=1;i<=n;i++)
{
int x;
x=(b[i]/div[dig])%10;
update(0,i,x,1);
}
//the prob comes here
int p=0;
for(int i=0;i<qidx[dig].size();i++)
{
//printf("qidx[%d].size()=%d\n",dig,qidx[dig].size());
for(int& j=p;j<optimes[qidx[dig][i]];j++)
{
//printf("!!!");
int x=op[j].x;
int y=op[j].y;
int p=(b[x]/div[dig])%10;
update(0,x,p,-1);
p=(y/div[dig])%10;
update(0,x,p,1);
b[x]=y;
}
int idx=qidx[dig][i];
q[idx].ans=sum(0,q[idx].r,q[idx].p)-sum(0,q[idx].l-1,q[idx].p);
}
}
for(int i=1;i<=m;i++)
{
if(q[i].ans!=-1)
cout<<q[i].ans<<"\n";
}
}
return 0;
}