zoj 1610 线段的涂色

要学会的是懒操作。这个题目跟北大的2777差不多,只是在计数的时候,有了变化。还有这个题目建树的时候需要注意一下。我建树建立错误,得到Segmentation Fault ,从来没遇到过这样的错误,现在长见识了。现在得好好总结一下这种线段树的做法了。类似于线段涂色的这种题目,建树要建立到元线段,而非点。更新的时候,要利用懒操作。没必要更新到叶子节点,主要是那样太浪费时间。如果更新父节点所在区间的一部分并且更新的时候同父节点原来保存的信息部哟样的话,需要先把父节点的信息传到孩子节点,对父节点进行特殊的标记,这样可以知道这个父节点所在区间保存的信息部唯一。这可能就是懒操作吧!感觉线段树有很多的变形,很灵活,要想很好的掌握,还得多练习啊!

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define N 8015
struct SegTree
{
    int l,r,mid;
    int col;
}tree[N*4];
int len[N],col[N];
void BuildTree(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].mid=(l+r)>>1;
    tree[root].col=-1;
    if(l+1==r)return;
    BuildTree(2*root,l,tree[root].mid);
    BuildTree(2*root+1,tree[root].mid,r);
}
void Updata(int root,int l,int r,int c)
{
    if(l<=tree[root].l&&tree[root].r<=r)
    {
        tree[root].col=c;
        return;
    }
    if(tree[root].col==c)return;
    if(tree[root].col>=0)
    {
        tree[2*root].col=tree[root].col;
        tree[2*root+1].col=tree[root].col;
        tree[root].col=-1;               //将父节点置为-1,表明这个区间上不止一种颜色
    }
    if(r<=tree[root].mid)Updata(2*root,l,r,c);
    else if(l>=tree[root].mid)Updata(2*root+1,l,r,c);
    else
    {
        Updata(2*root,l,tree[root].mid,c);
        Updata(2*root+1,tree[root].mid,r,c);
    }
}
void count(int root,int l,int r)
{
    if(tree[root].col>=0)  //表明这个父节点所覆盖的区间只有一种颜色
    {
        for(int i=l;i<r;i++)
        {
            col[i]=tree[root].col;
        }
        return;
    }
    if(tree[root].l+1==tree[root].r)return ;
    if(r<=tree[root].mid)count(2*root,l,r);
    else if(l>=tree[root].mid)count(2*root+1,l,r);
    else
    {
        count(2*root,l,tree[root].mid);
        count(2*root+1,tree[root].mid,r);
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int t=n;
        BuildTree(1,0,8000);
        while(t--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            Updata(1,a,b,c);
        }
        memset(col,-1,sizeof(col));
        memset(len,0,sizeof(len));
        count(1,0,8000);
        for(int i=0;i<N;i++)
        {
            if(col[i+1]!=col[i]&&col[i]!=-1)
            {
                len[col[i]]++;
            }
        }
        for(int i=0;i<N;i++)
        {
            if(len[i])printf("%d %d\n",i,len[i]);
        }
        printf("\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值