HDU 4391 Paint The Wall

多校赛的题目 , 有趣吧 。。
这道题,包大人讲完之后,还是束手无策,因为线段树听说会超时。。
这题目,我觉得就是线段树啊。。
于是新做法有了,分块hash。
一听到这个名字,hash,难道要%mod?? 这怎么办,一脸懵逼
然后搜题解了,
http://blog.csdn.net/acm_cxlove/article/details/8146271—ACM_cxlove的博客。。
感谢巨巨的代码,初看的时候还是一脸懵逼,但是照着他的代码抄一遍之后,就理解了。。分块hash 真的是个神奇的东西啊。。
不过现在我还不知道什么时候用分块hash。。

具体的内容都注释了, 也就是解释一下巨巨的代码了。。
然后在他的博客里面居然看到了WYQ学长大人的留言,哇。感觉好有趣。。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cmath>
using namespace std;
const int MAXN = 100005;
int n;
int len;
struct myhash
{
    int size;
    int color;
    map<int,int>mycolor;
}hashwall[1000000];
int mywall[MAXN];
void build()//具体做法:首先我们把全场分成许多相同长度的部分。
{
    len = (int)sqrt(n);//这一步最重要,选择sqrt因为这是平均分配,长度相同嘛。。
    int all = (n - 1) / len + 1; // 这里,需要初始化啦,所以,我们要求出有多少区间
    for(int i = 0; i < all ; ++ i )
    {
        hashwall[i].size =  min((i + 1) * len , n ) - i * len; //size 记录的是每个区间的长度。。
        hashwall[i].color = -1;//记录的是这个区间的颜色,if color != -1 ;那么这个区间就是这个颜色,else 这个区间是无色或者混色。。
        hashwall[i].mycolor.clear();//记录这个区间颜色的数目。。
    }
    for(int i = 0; i < n ; ++ i)
    {
        scanf("%d", &mywall[i]);//mywall 这个东西 我觉得就是在模拟。。
        hashwall[i / len].mycolor[mywall[i]]++;//记录数目。。
    }
}
void myson(int who)//这个似乎想到了线段树的lazy,这里的作用是用把父节点保存的颜色更新子节点。。
{
    if(hashwall[who].color != -1)
    {
        hashwall[who].mycolor.clear();
        for(int i = who * len; i < min((who + 1) * len , n ); ++ i)
        {
            mywall[i] = hashwall[who].color;
            hashwall[who].mycolor[mywall[i]] ++;// 更新。。
        }
        hashwall[who].color = -1;
    }
}
void change(int left ,int right ,int color)
{
    int hashl = left / len;//这里就是找到所在的区间
    int hashr = right / len;
    for(int i = hashl + 1; i < hashr ; ++ i)//如果是多个区间在一起,这样中间德区间记录一下color,表示这个区间的颜色就是color,等到需要单独更新的时候再更新就可以了,很想线段树的lazy啊。。
    {
        hashwall[i].color = color ;
    }
    if(hashl != hashr)//那么这是候,left 到hashl的长度就需要单独的更新,right同理。。
    {
        myson(hashl);// 首先要明确hashl的区间的范围是 hashl*len到(hashl+1)*len,hash1*len一定小于等于left,所以left包含在其中,这样就要更新一下hashl,因为,更新后此时hashwall【hashl】。color已经不能代表hashl这个区间的颜色了。。
        myson(hashr); // 同理。。
        for(int i = left ; i < (hashl + 1) * len ; ++ i )
        {
            hashwall[hashl].mycolor[mywall[i]] --;// 减去旧的颜色
            hashwall[hashl].mycolor[color] ++;// 加上新的颜色
            mywall[i] = color ;// 储存更新后的颜色,现在这个颜色对于下一轮来说就是旧的颜色了。。
        }
        for(int i = hashr * len ; i <= right ; ++ i)// 同理
        {
            hashwall[hashr].mycolor[mywall[i]] --;
            hashwall[hashr].mycolor[color] ++;
            mywall[i] = color;
        }
    }
    else// 当只在一个区间发生就直接 left 到 right 模拟一下了。。
    {
        myson(hashl);
        for(int i = left ;i <= right ; ++ i)
        {
            hashwall[hashl].mycolor[mywall[i]] --;
            hashwall[hashl].mycolor[color] ++;
            mywall[i] = color;
        }
    }
}
int query(int left, int right ,int color)
{
    int hashl = left / len;
    int hashr = right / len;
    int ans = 0;
    for(int i = hashl + 1 ; i < hashr ; ++ i)
    {
        if(hashwall[i].color == color)// hashwall[i].color代表这个区间的颜色
        {
            ans = ans + hashwall[i].size;
        }
        else if(hashwall[i].color == -1 && hashwall[i].mycolor.find(color) != hashwall[i].mycolor.end()) //混色的话,就问一下有没有这个颜色,有的话就加上这个颜色。。
        {
            ans = ans + hashwall[i].mycolor[color];
        }
    }
    if(hashl != hashr)
    {
        myson(hashl);
        myson(hashr);
        for(int i = left; i < (hashl + 1) * len; ++ i)
        {
            if(mywall[i] == color)// myson之后mywall【i】表示的就是当前这个点的颜色了。。
            {
                ++ ans;
            }
        }
        for(int i = hashr * len; i <= right; ++ i)
        {
            if(mywall[i] == color)
            {
                ++ ans;
            }
        }
    }
    else
    {
        myson(hashl);
        for(int i = left; i <= right; ++ i)
        {
            if(mywall[i] == color)
            {
                ++ ans;
            }
        }
    }
    return ans;
}
int main()
{
    int m;
    while(~scanf("%d%d", &n, &m))
    {
        build();
        int how , left , right ,color;
        while(m --)
        {
            scanf("%d%d%d%d", &how , &left , &right , &color);
            if(left > right)
            {
                swap(left , right);
            }
            if(how == 1)
            {
                change(left , right , color );
            }
            else
            {
                printf("%d\n", query(left , right , color));
            }
        }
    }
    return 0;
}

你可能感兴趣的:(HDU,分块hash)