ZOJ1610Count the Colors(线段树成段更新染色)

本文介绍了一种在固定长度线段上进行区间染色的算法实现。通过建立线段树来记录不同颜色区间的分布情况,并计算每种颜色形成的不连续区间数量。此算法适用于解决区间覆盖与查询的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610


题目大意:

在一条长度为8000的线段上染色,每次把区间[a,b]染成c颜色。显然,后面染上去的颜色会覆盖掉之前的颜色。

求染完之后,每个颜色在线段上有多少个间断的区间。


注意:

因为染色的是区间,是从最左边的向右开始染色,所以更新的时候左端点可以加1。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 8005;
int n, col[maxn<<2], vis[maxn<<2], ans[maxn];
void inline push_down(int rt)
{
    col[rt<<1] = col[rt<<1|1] = col[rt];
    col[rt] = -1;
}
void update(int rt, int left, int right, int l, int r, int data)
{
    if(l <= left && right <= r)
    {
        col[rt] = data;
        return;
    }
    if(col[rt] == data)
        return;
    if(col[rt] != -1)
        push_down(rt);
    int mid = (left + right) >> 1;
    if(l <= mid)
        update(rt<<1, left, mid, l, r, data);
    if(r > mid)
        update(rt<<1|1, mid+1, right, l, r, data);
}
void query(int rt, int left, int right)
{
    if(col[rt] >= 0)
    {
        for(int i = left; i <= right; i++)
            vis[i] = col[rt];
        return;
    }
    if(left < right && col[rt] == -1)
    {
        int mid = (left+right) >> 1;
        query(rt<<1, left, mid);
        query(rt<<1|1, mid+1, right);
    }
}
int main()
{
    int u, v, w;
    while(scanf("%d", &n) != EOF)
    {
        memset(col, -1, sizeof(col));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            if(u >= v)
                continue;
            update(1, 1, 8000, u+1, v, w);
        }
        memset(vis, -1, sizeof(vis));
        query(1, 1, 8000);
        memset(ans, 0, sizeof(ans));
        int i = 1;
        while(i <= 8000)
        {
            int color = vis[i], j = i + 1;
            if(color == -1)
            {
                ++i;
                continue;
            }
            while(vis[j] == color && j <= 8000)
                ++j;
            ++ans[color];
            i = j;
        }
        for(int i = 0; i <= 8000; i++)
            if(ans[i])
                cout << i << " " << ans[i] << endl;
        puts("");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值