题意还是很简单的,Q是查询,S是重新设置数,
一开始用线段树三维数组做的,内存估计有100000*4*10*10,结果超内存了,意料之内,纯粹是想复习一下线段树
后来才学到降维,降低空间牺牲时间,
代码一:
离线树状数组(离线:就是指把操作放一起,每次都要把操作遍历一遍,更新结果数组ans,最后统一把结果输出)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#define pi (acos(-1.0))
#define eps (1e-6)
#define inf (1<<28)
#define mod 1000000007
#define MAXN 100010
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
#define MAX 100100
int lowbit(int t){return t&(-t);}
int getsum(int array[][MAX],int t,int pos)
{
int s = 0;
while(t)
{
s += array[pos][t];
t -= lowbit(t);
}
return s;
}
void insert(int array[][MAX],int t,int num,int m,int pos)
{
while(t <= m)
{
array[pos][t] += num;
t += lowbit(t);
}
}
struct REC
{
int l,r,pos,dig,index,val;
char ch;
}rec[MAX];
int T,N,M;
int ans[MAX],a[MAX],a_c[MAX],arr[10][MAX];
int main()
{
int i,j,pow10;
cin>>T;
while(T--){
cin>>N>>M;
for(i=0;i<N;i++){
scanf("%d",&a[i]);
a_c[i]=a[i];//每次离线操作都会初始化成最开始的状态,预存一个a的副本a_c
}
for(i=0;i<M;i++){
cin>>rec[i].ch;
if(rec[i].ch=='Q') scanf("%d%d%d%d",&rec[i].l,&rec[i].r,&rec[i].pos,&rec[i].dig);
else scanf("%d%d",&rec[i].index,&rec[i].val);
}
int pow10=1;
for(i=1;i<=10;i++,pow10*=10){//第i位
memset(arr,0,sizeof(arr));
for(j=0;j<N;j++) {
a[j]=a_c[j];//a恢复初始状态
insert(arr,j+1,1,N,(a[j]/pow10)%10);//第i位上具体哪个数值
}
for(j=0;j<M;j++){
if(rec[j].ch=='S'){
insert(arr,rec[j].index,-1,N,(a[rec[j].index-1]/pow10)%10);//上次的数值减掉
insert(arr,rec[j].index,1,N,(rec[j].val/pow10)%10);//这次的数值加上
a[rec[j].index-1]=rec[j].val;//记下这次的数值,注意这里a变化了,下次离线求和初始化的时候a需要变成初始状态
}
else if(rec[j].pos==i) ans[j]=getsum(arr,rec[j].r,rec[j].dig)-getsum(arr,rec[j].l-1,rec[j].dig);
}
}
for(j=0;j<M;j++)
if(rec[j].ch=='Q')
printf("%d\n",ans[j]);
}
}
代码二:分块
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#define pi (acos(-1.0))
#define eps (1e-6)
#define inf (1<<28)
#define mod 1000000007
#define MAXN 100010
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int N = 100010;
int block[400][10][10]={0};
int pp[10];
int a[N];
int _,n,m,cnt;
void build()
{
int i,j;
int tmp = sqrt(n*1.0);
cnt = n / tmp + 1;
int id;
memset(block,0,sizeof(block));
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
id = i / cnt;
tmp = a[i];
for(j = 0 ;j < 10;j++)
{
block[id][j][tmp%10]++;
tmp /= 10;
}
}
}
int query(int l,int r,int dig,int num)
{
int L = l/cnt,R = r/cnt;
int i,j,div = pp[dig];
int res = 0;
if(L == R)
{
for(i=l;i<=r;i++)
if(a[i]/div%10 == num)
res++;
return res;
}
for(i = L+1;i<R;i++)
res += block[i][dig][num];
for(i = l;i<(L+1)*cnt;i++)
if(a[i]/div%10 == num)
res++;
for(i = R*cnt;i<=r;i++)
if(a[i]/div%10 == num)
res++;
return res;
}
void update(int x,int num)
{
int i;
int id = x / cnt;
for(i=0;i<10;i++)
{
block[id][i][a[x]%10]--;
a[x] /= 10;
}
a[x] = num;
for(i=0;i<10;i++)
{
block[id][i][num%10]++;
num /= 10;
}
}
void solve()
{
scanf("%d%d",&n,&m);
build();
char str[5];
int x,num;
int l,r;
while(m--)
{
scanf("%s",str);
if(str[0] == 'S')
{
scanf("%d%d",&x,&num);
x--;
update(x,num);
}
else
{
scanf("%d%d%d%d",&l,&r,&x,&num);
l--,r--,x--;
printf("%d\n",query(l,r,x,num));
}
}
}
void init()
{
int i;
pp[0] = 1;
for(i=1;i<10;i++)
pp[i] = pp[i-1] * 10;
}
int main()
{
init();
cin>>_;
while(_--) solve();
return 0;
}
代码三(错的) 线段树 留个记录吧
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#define pi (acos(-1.0))
#define eps (1e-6)
#define inf (1<<28)
#define mod 1000000007
#define MAXN 100010
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
int v[MAXN<<2][20][10]={0};
int nn;
int max_dig,max_nozero;
void push_up(int rt)
{
int i,j;
for(i=1;i<=20;i++)
for(j=0;j<10;j++)
v[rt][i][j] = v[rt<<1][i][j] + v[rt<<1|1][i][j];
}
void build(int l,int r,int rt)
{
if(l == r)
{
int num,cnt;
memset(v[rt],0,sizeof(v[rt]));
scanf("%d",&num);
int i = 1;
cnt = 0;
while(num)
{
cnt++;
v[rt][i++][num%10]++;
num /= 10;
}
if(cnt >= max_dig)
{
if(cnt == max_dig)
max_nozero++;
else
max_nozero = 1;
max_dig = cnt;
}
return ;
}
int m = (l+r)>>1;
build(ls);
build(rs);
push_up(rt);
}
void update(int x,int num,int l,int r,int rt)
{
if(l == x && r == x)
{
int i = 1,cnt = 0;
memset(v[rt],0,sizeof(v[rt]));
while(num)
{
cnt++;
v[rt][i++][num%10]++;
num /= 10;
}
if(cnt >= max_dig)
{
if(cnt == max_dig)
max_nozero++;
else
max_nozero = 1;
max_dig = cnt;
}
return ;
}
int m = (l+r)>>1;
if(x <= m)
update(x,num,ls);
else
update(x,num,rs);
push_up(rt);
}
int query(int L,int R,int dig,int num,int l,int r,int rt)
{
if(L <= l && R >= r)
return v[rt][dig][num];
int res = 0;
int m = (l+r)>>1;
if(L <= m)
res += query(L,R,dig,num,ls);
if(R > m)
res += query(L,R,dig,num,rs);
return res;
}
int main()
{
int i,j,k,N,flag;
LL temp;
int T,t,limit,pos;
int mm,x,y;
int L,R,dig,num;
char vis;
scanf("%d",&T);
while(T-- && scanf("%d%d",&nn,&mm))
{
max_dig = max_nozero = 0;
build(1,nn,1);
scanf("%*c");
while(mm--)
{
scanf("%c",&vis);
if(vis == 'Q')
{
scanf("%d%d%d%d%*c",&L,&R,&dig,&num);
if(num == 0 && dig >= max_dig)
{
if(dig == max_dig)
printf("%d\n",nn - max_nozero);
else
printf("%d\n",nn);
continue;
}
printf("%d\n",query(L,R,dig,num,1,nn,1));
}
else
{
scanf("%d%d%*c",&L,&num);
update(L,num,1,nn,1);
}
}
}
return 0;
}