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];

减少空间开辟。

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 100000 + 10;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Block{
    map<int, int> num;
    int lazy, L, R;
}b[1000];
int belong[maxn], a[maxn], block, sz;
int n, m;
void init(){
    block = sqrt(n * 1.0);
    for(int i = 0; i < n; i++)
        belong[i] = i / block + 1;
    sz = belong[n - 1];
    for(int i = 1; i <= sz; i++){
        b[i].lazy = -1;
        b[i].L = (i - 1) * block;
        b[i].R = min(b[i].L + block - 1, n - 1);
        b[i].num.clear();
        for(int j = b[i].L; j <= b[i].R; j++){
            b[i].num[a[j]]++;
        }
    }
}
void push_down(int x){
    b[x].num.clear();
    for(int i = b[x].L; i <= b[x].R; i++)
        a[i] = b[x].lazy;
    b[x].num[b[x].lazy] = b[x].R - b[x].L + 1;
    b[x].lazy = -1;
}
void update(int ll, int rr, int z){
    int l = belong[ll], r = belong[rr];
    int L, R;
    if(l == r){
        if(b[l].lazy != -1) push_down(l);
        for(int i = ll; i <= rr; i++){
            b[l].num[a[i]]--;
            b[l].num[z]++;
            a[i] = z;
        }
    }
    else{
        L = ll, R = b[l].R;
        if(b[l].lazy != -1) push_down(l);
        for(int i = L; i <= R; i++){
            b[l].num[a[i]]--;
            b[l].num[z]++;
            a[i] = z;
        }

        L = l + 1, R = r - 1;
        for(int i = L; i <= R; i++)
            b[i].lazy = z;

        L = b[r].L, R = rr;
        if(b[r].lazy != -1) push_down(r);
        for(int i = L; i <= R; i++){
            b[r].num[a[i]]--;
            b[r].num[z]++;
            a[i] = z;
        }
    }
}
int query(int ll, int rr, int z){
    int l = belong[ll], r = belong[rr];
    int L, R, ans = 0;

    if(l == r){
        if(b[l].lazy != -1) push_down(l);
        for(int i = ll; i <= rr; i++){
            if(a[i] == z) ans++;
        }
        return ans;
    }
    else{
        L = ll, R = b[l].R;
        if(b[l].lazy != -1) push_down(l);
        for(int i = L; i <= R; i++){
            if(a[i] == z) ans++;
        }

        L = l + 1, R = r - 1;
        for(int i = L; i <= R; i++){
            if(b[i].lazy != -1){
                if(b[i].lazy == z) ans += b[i].R - b[i].L + 1;
            }
            else{
                if(b[i].num.find(z) != b[i].num.end()) ans += b[i].num[z];  //不开辟新空间
            }
        }

        L = b[r].L, R = rr;
        if(b[r].lazy != -1) push_down(r);
        for(int i = L; i <= R; i++){
            if(a[i] == z) ans++;
        }
        return ans;
    }
}
int main(){
    while(~scanf("%d%d", &n, &m)){
        for(int i = 0; i < n; i++){
            scanf("%d", &a[i]);
        }
        init();
        while(m--){
            int o, l, r, z;
            scanf("%d%d%d%d", &o, &l, &r, &z);
            if(o == 1){
                update(l, r, z);
            }
            else{
                printf("%d\n", query(l, r, z));
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/KirinSB/p/10574641.html

时间: 2024-11-07 10:46:35

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

通道 题意:区间涂色,询问区间内颜色相同的个数 思路:将原区间划分乘sqrt(n)个区间,每次暴力查询和跟新两边的区间,中间的区间直接用hash存每种颜色的节点的数量.这里用到了类似线段树的lazy思想,区间成段修改直接打个标记,等到要划分这个区间的时候先把标记传下去,然后更新 代码: #include <stdio.h> #include <math.h> #include <string.h> #include <map> #define MAXN 10

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 1556 Color the ball(线段树区间维护+单点求值)

传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25511    Accepted Submission(s): 12393 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele

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 5009 Paint Pearls(西安网络赛C题)

HDU 5009 Paint Pearls 题目链接 题意:给定一个目标颜色,每次能选一个区间染色,染色的代价为这个区间不同颜色数的平方,问最小代价 思路:先预处理,把相同颜色的一段合并成一个点,然后把颜色离散化掉,然后进行dp,dp[i]表示染到第i个位置的代价,然后往后转移,转移的过程记录下不同个数,这样就可以转移了,注意加个剪枝,就是如果答案大于了dp[n]就不用往后继续转移了 代码: #include <cstdio> #include <cstring> #include