HDU 1199 Color the Ball(离散化入门+非线段树做法)

6 篇文章 0 订阅
1 篇文章 0 订阅

HDU 1199 Color the Ball

题意

  1. 一个数轴,数轴上点的坐标从1~1e9
  2. 一共有n次操作,以a,b,c形式输入,是把a~b的这段区间染色成白色/黑色
  3. 询问n次操作后,最长的连续白色区间,输出区间的左端点和右端点

解决

  1. 注意到点的范围很大,而且只有2000个区间,4000个点,点十分稀疏,不能使用普通数组进行存储
  2. 初学离散化,这是我做的第一道离散化的题(新手入门,还望见谅)
  3. 刚开始是想离散化后只有4000个点,直接暴力模拟一遍,样例过了但是被wa了
  4. 后来和队友交流的时候,发现对于14 16 w 、 19 20 w这样的操作,我的程序在便利的时候会把17~18的这一段也当成白色的,进而得到14~20这样的错误区间,还有一个问题就是对于1 4 w、3 5 b这样的操作,我的程序并不能得到1~2均为白色,而是把1当做单一的白色节点来处理。
  5. 解决上述错误:我在离散化的时候,把a-1 a+1 a b-1 b+1 b都做了离散化,这样的话,就不会影响到相邻点了。

继续拿14 16 w 、 19 20 w的操作为例
在执行完这两个操作后应该是这样的情况

13  ->  无色
14  ->  白色
15  ->  白色
16  ->  白色
17  ->  无色
18  ->  无色
19  ->  白色
20  ->  白色
21  ->  无色

那么我们就能解决掉程序无法判断17~18仍为无色的问题,进而得不到14~20这个不合法的区间

同样,我们拿1 4 w、3 5 b的例子再来看一下为什么+1和-1就能解决这个问题
在执行上述操作后,应该是这个情况

0   ->  无色                          0   ->  无色
1   ->  白色                          1   ->  白色
2   ->  白色        3 5 b             2   ->  白色
3   ->  白色      ------>>>>          3   ->  黑色
4   ->  白色                          4   ->  黑色
5   ->  无色                          5   ->  黑色
6   ->  无色                          6   ->  无色

如果没有理解,可以自己在草稿纸上模拟一下

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<cstdio>
using namespace std;
int a[2005] , b[2005] , c[2005];
int num[13000];                 //用来保存离散化后的点的状态,0为无色,-1为黑色,1为白色
vector<int> V;                  //一个区间会被拆成6个点,所以开6x2000的数组
map<int,int> val2key;           //真实值(val)到离散化后的值(key)的映射关系
map<int,int> key2val;           //离散化后的值(key)到真实值(val)的映射关系
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(num,0,sizeof(num));
        V.clear();
        val2key.clear();
        key2val.clear();
        for(int i=0;i<n;i++){
            scanf("%d %d %c",&a[i],&b[i],&c[i]);
            V.push_back(a[i]);
            V.push_back(a[i]-1);
            V.push_back(a[i]+1);
            V.push_back(b[i]);
            V.push_back(b[i]-1);
            V.push_back(b[i]+1);
        }

        //离散化操作
        sort(V.begin() , V.end());
        int len = unique(V.begin(),V.end())-V.begin();
        for(int i=0;i<len;i++){
            val2key[V[i]] = i+1;
            key2val[i+1] = V[i];
        }

        for(int i=0;i<n;i++){
            int l = val2key[a[i]];
            int r = val2key[b[i]];
            if(c[i]=='w'){
                for(int j=l;j<=r;j++)   num[j] = 1;
            }
            else if(c[i]=='b'){
                for(int j=l;j<=r;j++)   num[j] = -1;
            }
        }
        //for(int i=1;i<=len;i++) printf("%4d%c",i,i==len?'\n':' ');
        //for(int i=1;i<=len;i++) printf("%4d%c",num[i],i==len?'\n':' ');
        int ans = -1;
        int ans1,ans2;
        for(int i=1;i<=len;i++){
            int j = i;
            int tmp;            //真实长度
            if(num[i]==-1||num[i]==0) continue;
            while(num[j]==1) j++;
            tmp = key2val[j-1]-key2val[i]+1;
            //printf("%d len  =  %d\n",i,tmp);
            if(tmp>ans){
                ans = tmp;
                ans1 = key2val[i];
                ans2 = key2val[j-1];
            }
            i = j-1;
        }

        if(ans==-1) printf("Oh, my god\n");
        else printf("%d %d\n",ans1,ans2);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值