【分块】 HDU 4391 Paint The Wall

通道

题意:区间涂色,询问区间内颜色相同的个数

思路:将原区间划分乘sqrt(n)个区间,每次暴力查询和跟新两边的区间,中间的区间直接用hash存每种颜色的节点的数量。这里用到了类似线段树的lazy思想,区间成段修改直接打个标记,等到要划分这个区间的时候先把标记传下去,然后更新

代码:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <map>
#define MAXN 100005
int n,m,bsize,bnum,x[MAXN];
struct hash_block{
     int cls,size;
     std::map<int,int> mp;
}b[350];
void pushdown(int id){
    hash_block &hb=b[id];
    if(hb.cls!=-1){
        for(int i=id*bsize;i<id*bsize+hb.size;i++)x[i]=hb.cls;
        hb.mp.clear(),hb.mp[hb.cls]=hb.size;
        hb.cls=-1;
    }
}
void update(int l,int r,int c){
    int lb=l/bsize,rb=r/bsize,ans=0;
    for(int i=lb+1;i<rb;i++)b[i].cls=c;
    if(lb!=rb){
        pushdown(lb);pushdown(rb);
        for(int i=l;i<lb*bsize+b[lb].size;i++)
            b[lb].mp[x[i]]--,b[lb].mp[c]++,x[i]=c;
        for(int i=rb*bsize;i<=r;i++)
            b[rb].mp[x[i]]--,b[rb].mp[c]++,x[i]=c;
    }else{
    pushdown(lb);
    for(int i=l;i<=r;i++)
        b[lb].mp[x[i]]--,b[lb].mp[c]++,x[i]=c;
    }
}
int query(int l,int r,int c){
    int lb=l/bsize,rb=r/bsize,ans=0;
    for(int i=lb+1;i<rb;i++){
        if(b[i].cls==c)ans+=b[i].size;
        else if(b[i].cls==-1&&b[i].mp.find(c)!=b[i].mp.end())ans+=b[i].mp[c];
    }
    if(lb!=rb){
        pushdown(lb);pushdown(rb);
        for(int i=l;i<lb*bsize+b[lb].size;i++)ans+=(x[i]==c);
        for(int i=rb*bsize;i<=r;i++)ans+=(x[i]==c);
    }else{
        pushdown(lb);
        for(int i=l;i<=r;i++)ans+=(x[i]==c);
    }
    return ans;
}
void initblock(){
    bsize=(int)sqrt(n+1e-8);
    bnum=(n-1)/bsize+1;
    for(int i=0;i<bnum;i++){
        b[i].mp.clear();
        b[i].cls=-1;
        b[i].size=std::min(i*bsize+bsize,n)-i*bsize;
    }
    for(int i=0;i<n;i++){
        scanf("%d",&x[i]);
        b[i/bsize].mp[x[i]]++;
    }
}
int q,l,r,z;
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        initblock();
        while(m--){
            scanf("%d%d%d%d",&q,&l,&r,&z);
            if(q==1)update(l,r,z);
            else printf("%d\n",query(l,r,z));
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Rojo/p/4736353.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值