hdu5057  树状数组

来源:互联网 发布:免费手机视频制作软件 编辑:程序博客网 时间:2024/05/17 01:05

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

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

解法:这题一上来自然就敲了一个线段树 然而空间要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;}


0 0