HDU 4391 Paint The Wall [分块哈希]

  给出一个区间以及两种区间操作,[1 l,r,c]把l~r的点染成c色,[2,l,r,c]查询l~r内颜色为c的点的数目。

  因为c的数目太大,用线段树是存不下的,所以只能另辟蹊径了。虽然网上有线段树的方法,但那个Max-Min剪枝完全是没有作用的,随便出一组数据,把所有点间隔染成3,5,然后查4,这样用线段树不知道要跑多久。。。

  题解说这题是裸的分块HASH。。还没写过,学习了。其实就是将原区间划分乘sqrt(n)个区间,每次暴力查询和跟新两边的区间,中间的区间直接用hash存每种颜色的节点的数量。这里用到了类似线段树的lazy思想,区间成段修改直接打个标记,等到要划分这个区间的时候先把标记传下去,然后跟新。

  复杂度可以保证在每次操作sqrt(n)左右,这里为了方便我就直接写map了。。

  

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <string.h>
 4 #include <map>
 5 #define MAXN 100005
 6 int n,m,bsize,bnum,x[MAXN];
 7 struct hash_block{
 8      int cls,size;
 9      std::map<int,int> mp;
10 }b[350];
11 //下传标记,当这个块化整为零的时候需要下传标记并跟新所有元素
12 void pushdown(int id){
13     hash_block &hb=b[id];
14     if(hb.cls!=-1){
15         for(int i=id*bsize;i<id*bsize+hb.size;i++)x[i]=hb.cls;
16         hb.mp.clear(),hb.mp[hb.cls]=hb.size;
17         hb.cls=-1;
18     }
19 }
20 //跟新,中间的部分打标记就可以了,两边的sqrt(n)暴力跟新
21 void update(int l,int r,int c){
22     int lb=l/bsize,rb=r/bsize,ans=0;
23     for(int i=lb+1;i<rb;i++)b[i].cls=c;
24     if(lb!=rb){
25         pushdown(lb);pushdown(rb);
26         for(int i=l;i<lb*bsize+b[lb].size;i++)
27             b[lb].mp[x[i]]--,b[lb].mp[c]++,x[i]=c;
28         for(int i=rb*bsize;i<=r;i++)
29             b[rb].mp[x[i]]--,b[rb].mp[c]++,x[i]=c;
30     }else{
31     pushdown(lb);
32     for(int i=l;i<=r;i++)
33         b[lb].mp[x[i]]--,b[lb].mp[c]++,x[i]=c;
34     }
35 }
36 //中间的部分根据标记或者hash表可以直接查询,两边的sqrt(n)暴力查询
37 int query(int l,int r,int c){
38     int lb=l/bsize,rb=r/bsize,ans=0;
39     for(int i=lb+1;i<rb;i++){
40         //一直错在这个地方了,如果有标记,直接判断标记是不是需要的颜色
41         //如果没标记,要先判map中有没有这个元素然后在操作,否则会MLE!
42         if(b[i].cls==c)ans+=b[i].size;
43         else if(b[i].cls==-1&&b[i].mp.find(c)!=b[i].mp.end())ans+=b[i].mp[c];
44     }
45     if(lb!=rb){
46         pushdown(lb);pushdown(rb);
47         for(int i=l;i<lb*bsize+b[lb].size;i++)ans+=(x[i]==c);
48         for(int i=rb*bsize;i<=r;i++)ans+=(x[i]==c);
49     }else{
50         pushdown(lb);
51         for(int i=l;i<=r;i++)ans+=(x[i]==c);
52     }
53     return ans;
54 }
55 void initblock(){
56     bsize=(int)sqrt(n+1e-8);
57     bnum=(n-1)/bsize+1;
58     for(int i=0;i<bnum;i++){
59         b[i].mp.clear();
60         b[i].cls=-1;
61         b[i].size=std::min(i*bsize+bsize,n)-i*bsize;
62     }
63     for(int i=0;i<n;i++){
64         scanf("%d",&x[i]);
65         b[i/bsize].mp[x[i]]++;
66     }
67 }
68 int q,l,r,z;
69 int main(){
70     //freopen("test.in","r",stdin);
71     while(scanf("%d%d",&n,&m)!=EOF){
72         initblock();
73         while(m--){
74             scanf("%d%d%d%d",&q,&l,&r,&z);
75             if(q==1)update(l,r,z);
76             else printf("%d\n",query(l,r,z));
77         }
78     }
79     return 0;
80 }
原文地址:https://www.cnblogs.com/swm8023/p/2698780.html