ZOJ 1606 Count the Colors (线段数染色)

题目大意:

给你一段长度为 8000 的绳子,n 次操作,每次将[ l  r ]区间染色为 c ,染色会覆盖掉之前的染色,所有数字不超过8000,统计最后的颜色和出现的不连续区间的个数。按颜色顺序输出。

 题解思路:

线段数区间染色,因为是区间染色,所以在每个2点之间又加了一个点来代表此区间的颜色。

最后统计区间个数用一个last标记一下上次的颜色即可,注意如果颜色断掉last要初始一下。

(这个数据范围,暴力不好吗)

几个样例

2

1 2 1

3 4 1

3

1 10 0

1 4  1

5 10 2

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>

const int maxn=16005;

using namespace std;

int col[4*maxn],n,cnt[maxn],last;

void built(int l,int r,int now)//初始化
{
    int mid=(l+r)/2;
    col[now]=-1;
    if(l==r) return ;
    built(l,mid,now*2);
    built(mid+1,r,now*2+1);
}

void updata(int l,int r,int left,int right, int c,int now)
{
    int mid=(l+r)/2;
    if(left<=l&&r<=right)
    {
        col[now]=c;
        return ;
    }
    if(l==r) return ;
    if(col[now]!=-1)//向下传递
    {
        col[now*2]=col[now*2+1]=col[now];
        col[now]=-1;
    }
    if(left<=mid) updata(l,mid,left,right,c,now*2);
    if(right>mid) updata(mid+1,r,left,right,c,now*2+1);
}

void query(int l,int r,int now)
{
    int mid=(l+r)/2;
    if(col[now]!=-1)
    {
        if(col[now]!=last)
        {
            cnt[col[now]]++;
            last=col[now];
        }
        return ;
    }
    if(l==r) {last=-1;return ;}//如果到了叶子节点且没有颜色,表示颜色断掉
    query(l,mid,now*2);
    query(mid+1,r,now*2+1);
}

int main(){
    while(~scanf("%d",&n))
    {
        built(0,16000,1);
        for(int i=1;i<=n;i++)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            updata(0,16000,2*l,2*r,k,1);//区间加点,直接*2处理了
        }
        last=-1;
        memset(cnt,0,sizeof(cnt));
        query(0,16000,1);
        for(int i=0;i<=8000;i++)
        {
            if(cnt[i]!=0)
            {
                printf("%d %d\n",i,cnt[i]);
            }
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2019-01-23 15:35  Minun  阅读(184)  评论(0编辑  收藏  举报