hdu-5057(离线的树状数组)

题意是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循环用时间换空间
 

询问操作是getsum(r,position)-getsum(l,position)

赋值操作不仅要update树状数组的某一位加一,还要update这一位之前的数值减一,所以每次赋值后还要记录下这次赋值的数据,下次很可能把这位赋值成其他数值,那么这次update加一操作还要减回去

#include
#include
#include
#include
#include
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;
}


你可能感兴趣的:(树状数组)