现在的位置: 首页 > 综合 > 正文

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

2018年02月22日 ⁄ 综合 ⁄ 共 3165字 ⁄ 字号 评论关闭
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");
    }
}

抱歉!评论已关闭.