hdu1199Color the Ball (线段树 段更新+离散化)

Problem Description
There are infinite balls in a line (numbered 1 2 3 ....), and initially all of them are paint black. Now Jim use a brush paint the balls, every time give two integers a b and follow by a char 'w' or 'b', 'w' denotes the ball from a to b are painted white, 'b' denotes that be painted black. You are ask to find the longest white ball sequence.

Input
First line is an integer N (<=2000), the times Jim paint, next N line contain a b c, c can be 'w' and 'b'.

There are multiple cases, process to the end of file.

Output
Two integers the left end of the longest white ball sequence and the right end of longest white ball sequence (If more than one output the small number one). All the input are less than 2^31-1. If no such sequence exists, output "Oh, my god".

Sample Input
  
  
3 1 4 w 8 11 w 3 5 b

Sample Output
  
  
8 11
题目意思是:w为白色段,b为黑色段,求出最长的白色段。 输入的点值不超过 2^31-1
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define N 4000
struct nn
{
    int l,r,c,b;//c=0为黑,否则为白,b=1时l~r段只为黑色(白色)
}root[10*N],init[N+5],d[10*N];//root用于建树,init用于保存输入,d用于找最长段
int node[3*N+5],n,x[3*N+5],dn;//x用于输入的点离散化,node用于存放离散化后的点,node[i]点的大小可用i代替一下
//------用于离散化时,点从小到大排------
int cmp(int a,int b)
{
    return a<b;
}
//-----用于重新设置离散化的点,去重并加入一些必要的点-----
void reset_node()
{
    int i,j;
    node[1]=x[1];
    for(i=2,j=1;i<=n;i++)
    {
        if(x[i]==node[j])//去重点
           continue ;
        if(node[j]+1<x[i])//加入必要的点使本不连续的点离散化后也要隔开
        node[++j]=node[j-1]+1;
        if(node[j]+1<x[i])
        node[++j]=x[i]-1;
        node[++j]=x[i];
    }
    n=j;//点的总个数
}
//-------找到点k在所有点按顺序排中的位置--------
int in_node(int k)
{
    int l=1,r=n,m;
    while(l<=r)
    {
        m=(l+r)/2;
        if(k==node[m]) break;
        if(k>node[m]) l=m+1;
        if(k<node[m]) r=m-1;
    }
    return m;
}
//-------只用于初始化建立线段树------
void set_tree(int l,int r,int k)
{
    int m=(l+r)/2;
    root[k].l=l; root[k].r=r;
    root[k].c=0; root[k].b=1;//每一段都是黑色,颜色单一
    if(l==r) return ;
    set_tree(l,m,2*k);  set_tree(m+1,r,2*k+1);
}
//------更新段L~R----------
int L,R,c;
void chang_color(int l,int r,int k)
{
    int m=(l+r)/2;
    if(L<=l&&r<=R){
        root[k].c=c; root[k].b=1;
        return ;
    }
    if(root[k].b&&root[k].c==c)
            return ;
    if(root[k].b){//更新左右子树,不然当前节点就要变成了颜色不单一
        root[k*2].b=root[k*2+1].b=1;
        root[k*2].c=root[k*2+1].c=root[k].c;
    }
    if(R<=m) chang_color(l,m,2*k);
    else if(L>m) chang_color(m+1,r,2*k+1);
    else {
        chang_color(l,m,2*k);
        chang_color(m+1,r,2*k+1);
    }
    root[k].b=0;
}
//-------最后把本来要更新的点但还没有更新到,就更新------
void fine_set(int l,int r,int k)
{
    int m=(l+r)/2;
    if(l==r) return ;
    if(root[k].b){
        root[k*2].b=root[k*2+1].b=1;
        root[k*2].c=root[k*2+1].c=root[k].c;
    }
    fine_set(l,m,2*k);
    fine_set(m+1,r,2*k+1);
}
//-------为找最长段做准备-------
void find_len(int l,int r,int k)
{
    if(root[k].b)
        d[dn++]=root[k];
      if(l==r)  return ;
    int m=(l+r)/2;
    find_len(l,m,2*k); find_len(m+1,r,2*k+1);
}
int main()
{
    int m,i,len;
    char s;
    while(scanf("%d",&m)>0)
    {
        for(i=1,n=0;i<=m;i++)
        {
            scanf("%d%d %c",&init[i].l,&init[i].r,&s);
            x[++n]=init[i].l; x[++n]=init[i].r;//存入点,用于离散化
            if(s=='w') init[i].c=1;
            if(s=='b') init[i].c=0;
        }
        sort(x+1,x+n+1,cmp);
        reset_node();
        set_tree(1,n,1);//初始化
        for(i=1;i<=m;i++)//更新段
        {
            L=in_node(init[i].l); R=in_node(init[i].r);
            if(init[i].c) c=1;
            else c=0;
            chang_color(1,n,1);
        }
        fine_set(1,n,1);//最后的更新
        len=0; dn=0;
        find_len(1,n,1);
        for(i=0;i<dn;i++)
        if(d[i].c)
        {
            int j=i;
            while(d[i+1].c!=0&&i+1<dn) i++;//找到断点,第i段是白,第i+1段是黑
            if(i+1==dn&&node[d[i].r]-node[d[j].l]+1>len)
            {
                len=node[d[i].r]-node[d[j].l]+1;
                R=node[d[i].r]; L=node[d[j].l];
            }
            if(node[d[i].l]-node[d[j].l]>len&&i+1<dn)
            {
                len=node[d[i].l]-node[d[j].l];
                R=node[d[i].l]; L=node[d[j].l];
            }
        }
        if(len)
        printf("%d %d\n",L,R);
        else
        printf("Oh, my god\n");
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值