【分块】 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;
}

时间: 2024-10-09 21:39:40

【分块】 HDU 4391 Paint The Wall的相关文章

HDU 4391 - Paint The Wall - 分块哈希入门

题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=4391 题意 : 给一段区间, 有两种操作 1 : 给 x 到 y 的区间染色为 z 2 : 查询 x 到 y 的区间内颜色z的数目 思路 : 这题的z最大2^31-1, 区间长度最大1e5, 用线段树将颜色离散化之后维护也存不下 所以用分块哈希, 将一个长度为n的区间分为sqrt(n)块分块维护, 每一块中都用map记录某些颜色的个数 分块哈希 : 修改, 查询一段区间, 对于完整覆盖到的区间,

HDU 4391 Paint The Wall(分块的区间维护)

题意:给出几个操作,把l-r赋值为z,询问l-r有几个z,其中z < INT_MAX 思路:因为z很大,所以很难直接用线段树去维护.这里可以使用分块来解决.我们可以让每个块用map去储存map[i]的个数,用类似线段树的lazy标记来给整个块更新,当需要对块内某些数操作时再pushdown. 注意一下不要随意开辟map的空间,在计算区间的z的个数时应采用 if(b[i].num.find(z) != b[i].num.end()) ans += b[i].num[z]; 减少空间开辟. 代码:

HDU 4391 Paint The Wall 线段树(水

题意: 给定n长的数组,m个操作 下面是每个点的颜色 下面m个操纵: 1 l r col 染色 2 l r col 询问区间内为col颜色的点数 == 就是普通的操作+区间内最大最小颜色数的优化,感觉很不科学... ==感觉可以卡掉这种写法..反正就是不科学嘛 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector>

HDU 4391 Paint The Wall 段树(水

意甲冠军: 特定n多头排列.m操作 以下是各点的颜色 以下m一种操纵: 1 l r col 染色 2 l r col 问间隔col色点 == 通的操作+区间内最大最小颜色数的优化,感觉非常不科学... ==感觉能够卡掉这样的写法..反正就是不科学嘛 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> usin

HDU 4012 Paint on a Wall (状态压缩+BFS)

Paint on a Wall Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 824    Accepted Submission(s): 321 Problem Description Annie wants to paint her wall to an expected pattern. The wall can be rep

HDU 4012 Paint on a Wall(状压+bfs)

Paint on a Wall Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 830    Accepted Submission(s): 325 Problem Description Annie wants to paint her wall to an expected pattern. The wall can be repr

HDU 4391 线段树+优化

Paint The Wall Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2783    Accepted Submission(s): 766 Problem Description As a amateur artist, Xenocide loves painting the wall. The wall can be co

hdu 3669 Cross the Wall(斜率优化DP)

题目连接:hdu 3669 Cross the Wall 题意: 现在有一面无限大的墙,现在有n个人,每个人都能看成一个矩形,宽是w,高是h,现在这n个人要通过这面墙,现在只能让你挖k个洞,每个洞不能重叠,每个洞需要消耗你挖的w*h,现在问你最小消耗多少. 题解: 设dp[i][j]为前j个人挖i个洞的最小消耗. 首先我们先将每个人按w排序,我们可以发现,排序后的h是递减的,因为如果不是递减的,可以把那个点消掉,因为w[k]<w[j]&&h[k]<h[j]的话,那么第k个人就可

HDU 5009 Paint Pearls _(:зゝ∠)_2014 ACM/ICPC Asia Regional Xi&#39;an Online

呵呵 #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> typedef long long ll; using namespace std; const int N = 5 * 10000 + 5; int xval[N], dep; int n, a[N], pre[N]; ll d[N]; int pos[300], dd; void work()