首页 > 其他 > 详细

hdu5057 分块处理,当数值大于数据范围时树状数组 真是巧 将大数据分为小数据来处理

时间:2014-09-29 23:10:22      阅读:354      评论:0      收藏:0      [点我收藏+]

这题说的给了100000个数有100000次操作 询问 L和R 区间内 在D位上为P的个数,用树状数组存 要开[10][10][100000]的int 开不了但是能开 这么大的unsign short 这样我们将这个树状数组一分为二 50000 个位前面 50000 为后面 我们知道unshort 范围在60000多显然这样是可以开的了

bubuko.com,布布扣
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
typedef __int64 ll;
const int maxn=100005;
unsigned short C[2][10][10][50005];
int n;
int lowbit(int x){
  return x&(-x);
}
void add(int op, int id, int floor, int x,int v){
    int ma=op==0?min(50000,n):n-50000;
    while(x<=ma){
        C[op][id][floor][x]+=v;
        x+=lowbit(x);
    }
}
int sum( int op, int id, int floor, int x){
    int ans=0;
    while(x>0){
        ans+=C[op][id][floor][x];
        x-=lowbit(x);
    }
    return ans;
}
int A[maxn];
int solve(int L, int R, int D, int P){
        int s=0;
        if(R>50000){
            s=sum(1,P,D,R-50000)+sum(0,P,D,50000);
        }else s= sum(0,P,D,R);
        if(L>50000){
            s=s-sum(1,P,D,L-50000-1)-sum(0,P,D,50000);
        }else s-=sum(0,P,D,L-1);
        return s;
}
int main()
{
     int cas,m;
     scanf("%d",&cas);
     while(cas--){
         scanf("%d%d",&n,&m);
         memset(C,0,sizeof(C));
         for(int i=1; i<=n; ++i)
         {
             scanf("%d",&A[i]);
             int t =A[i];
             int loc=0;
             int ko=i>50000?i-50000:i;
             int op=i>50000?1:0;
             while(loc<10){
                add(op,t%10,loc,ko,1);
                loc++;
                t/=10;
             }
         }
         char st[2];
         int L,R,D,P;
         for(int i=0; i<m; ++i){
              scanf("%s",st);
              if(st[0]==Q){
                   scanf("%d%d%d%d",&L,&R,&D,&P);
                   int ans=solve(L,R,D-1,P);
                   printf("%d\n",ans);
              }else{
                  int x,y;
                  scanf("%d%d",&x,&y);
                  int t=A[x];
                  int loc=0;
                  int lc=x;
                  int op;
                  if(x>50000) lc-=50000,op=1;
                  else op=0;
                  while(loc<10){
                      add(op,t%10,loc,lc,-1);
                      loc++;
                      t/=10;
                  }
                  A[x]=y;
                  t = y;
                  loc=0;
                  while(loc<10){
                      add(op,t%10,loc,lc,1);
                      loc++;
                      t/=10;
                  }
            }
         }
     }
     return 0;
}
View Code

还有一种操作 就是离线,将每个操作记下来, 10000次操作 做10次 先做在第一位 开一个【100000】【10】的数组,然后先存每个数的第一位,然后按照操作顺序回答所有有关第一位的询问,然后同样的操作第二位 第三位... 意思做了10次这样的整套查询操作

bubuko.com,布布扣
#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
using namespace std;
typedef __int64 ll;
const int maxn=100005;
int C[10][maxn];
int n,m;
int eps[10];
int chose(int V, int t){
   return V / eps[t] % 10;
}
int lowbit(int x){
  return x&(-x);
}
void add( int x, int id , int v){
     while(x<=n){
         C[id][x]+=v;
         x+=lowbit(x);
     }
}
int sum( int x, int id ){
    int ans=0;
    while(x>0){
       ans+=C[id][x];
       x-=lowbit(x);
    }
    return ans;
}
int A[maxn];
int B[maxn];
int ans[maxn];
int op[maxn],L[maxn],R[maxn],D[maxn],P[maxn];
bool use[11];
void inti(int lo){
    memset( C , 0 , sizeof( C ) );
    for(int i=1; i<=n; ++i){
        B[i]=A[ i ];
        int id=chose( B[ i ] , lo );
        add(i,id,1);
    }
}
void solve(int los){
     for(int i =0; i<m; ++i){
         if(op[i]==1){
              int x=L[i];
              add(x,chose(B[x],los),-1);
              B[x]=R[ i ];
              add( x , chose(B[x],los) , 1 );
         }else if( op[i]==2 && D[i]==los ){
              ans[i]=sum(R[i],P[i])-sum(L[i]-1,P[i]);
         }
     }
}
int main()
{
     eps[1]=1;
     for(int i=2; i<=10; ++i)
         eps[i]=eps[i-1]*10;
     int cas;
     scanf("%d",&cas);
     while(cas--){
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; ++ i){
            scanf("%d",&A[i]);
            A[i];
        }
        memset(use,false,sizeof(use));
        char ch[2];
        for(int i=0; i<m; ++i ){
            scanf("%s",ch);
             if(ch[0]==S){
                op[i]=1;
                scanf("%d%d",&L[i],&R[i]);
             }else{
                op[i]=2;
                scanf("%d%d%d%d",&L[i],&R[i],&D[i],&P[i]);
                use[ D[i] ] = true ;
             }
        }
        for(int i=1; i<=10; ++i){
             if(use[i]==false)continue;
             inti(i);
             solve(i);
        }
        for(int i=0; i<m; ++i){
             if(op[i]==2) printf("%d\n",ans[i]);
        }
     }
     return 0;
}
View Code

 

hdu5057 分块处理,当数值大于数据范围时树状数组 真是巧 将大数据分为小数据来处理

原文:http://www.cnblogs.com/Opaser/p/4001082.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!