URAL - 1019 - Line Painting(离散化+线段树)

题意:在区间[0, 10^9]上染黑白两种颜色,问最后最长的白段的起点和终点。(初始区间全白)

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1019

——>>看数据可知要离散化。。而题意可知可用线段树去解决。。

对于区间[x, y],因为点到点,不是段到段,所以,可让x表示[x, x+1],整个区间的最后一点不表示,转化成段到段来解决。。于是[x, y]转化为[x, y-1]。。

时间复杂度为O(n)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define lc (o<<1)
#define rc ((o<<1)|1)

const int maxn = 5000 + 10;

char cover[maxn<<3], color[maxn<<3];        //结点数已<<1,线段树结点再<<2,总<<3

int N, a[maxn], b[maxn], buf[maxn<<1], cnt;
char c[maxn];

void read() {
    cnt = 0;
    buf[++cnt] = 0;
    buf[++cnt] = 1000000000;
    for(int i = 1; i <= N; i++) {
        scanf("%d%d %c", a+i, b+i, c+i);
        buf[++cnt] = a[i];
        buf[++cnt] = b[i];
    }
}

void discretize() {
    sort(buf + 1, buf + 1 + cnt);
    cnt = unique(buf + 1, buf + 1 + cnt) - buf - 1;     //求个数要-1
}

void build(int o, int L, int R) {
    cover[o] = 0;
    if(L == R) return;
    int M = (L + R) >> 1;
    build(lc, L, M);
    build(rc, M + 1, R);
}

void pushdown(int o) {
    if(cover[o]) {
        cover[lc] = cover[rc] = cover[o];
        cover[o] = 0;
    }
}

void Insert(int o, int L, int R, int ql, int qr, char color) {
    if(ql <= L && R <= qr) {
        cover[o] = color;
        return;
    }
    pushdown(o);
    int M = (L + R) >> 1;
    if(ql <= M) Insert(lc, L, M, ql, qr, color);
    if(qr > M) Insert(rc, M+1, R, ql, qr, color);
}

void query(int o, int L, int R, int ql, int qr) {
    if(cover[o]) {      //我这个才正点!
        for(int i = L; i <= R; i++) color[i] = cover[o];
        return;
    }
    if(L == R) {
        color[L] = cover[o];
        if(color[L] == 0) color[L] = 'w';       //还是判一下
        return;
    }
    pushdown(o);
    int M = (L + R) >> 1;
    if(ql <= M) query(lc, L, M, ql, qr);
    if(qr > M) query(rc, M+1, R, ql, qr);
}

void solve() {
    for(int i = 1; i <= N; i++) {
        int A = lower_bound(buf + 1, buf + 1 + cnt, a[i]) - buf;
        int B = lower_bound(buf + 1, buf + 1 + cnt, b[i]) - buf;
        Insert(1, 1, cnt, A, B-1, c[i]);        //cnt个点,cnt-1段
    }
    query(1, 1, cnt, 1, cnt-1);     //只查cnt-1段
    int L = 0, R = 0, Max = 0;
    for(int i = 1; i < cnt; i++) {
        if(color[i] == 'w') {
            int l = i;
            while(i < cnt && color[i] == 'w') i++;
            int r = i;
            if(buf[r] - buf[l] > Max) {
                L = buf[l];
                R = buf[r];
                Max = R - L;
            }
        }
    }
    printf("%d %d\n", L, R);
}

int main()
{
    while(scanf("%d", &N) == 1) {
        read();
        discretize();
        build(1, 1, cnt);
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值