zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    如何解决WEB应用中文乱码问题
    js获取指定格式的时间字符串
    js 实现 Base64 编码的相互转换
    Sql Server 与 MySql 在使用 update inner join 时的区别
    VMware12创建新的虚拟机及设置硬件环境
    Sql Server 中使用日期遍历
    Linux 添加定时任务,crontab -e 命令与直接编辑 /etc/crontab 文件
    mysql 中 max_allowed_packet 查询和修改
    eclipse编译项目:Java @Override 注解报错的解决方法
    eclipse启动项目报错:java.lang.ClassNotFoundException: ContextLoaderListener
  • 原文地址:https://www.cnblogs.com/swm8023/p/2698780.html
Copyright © 2011-2022 走看看