zoj1610 Count the Colors 线段树 区间修改

注释很详细了

代码基本上都是对着kuangbin的抄的

#include <iostream>
#include <cstring>
///给出每一段的颜色 后面加入的覆盖前面的 求每种颜色有几个线段
///区间更新每一段的值 那么线段树中储存的是每一段的值
using namespace std;
const int N=8010;
inline int lson(int t){return t<<1;}
inline int rson(int t){return lson(t)|1;}
struct Node{
    int l,r,color;
    Node(int _l,int _r,int _c){l=_l;r=_r;color=_c;}
    Node(){}
}segTree[N<<2];
void built(int t,int l,int r)
{
    segTree[t]=Node(l,r,-1);
    if(l==r)return;
    int mid=(l+r)>>1;
    built(lson(t),l,mid);
    built(rson(t),mid+1,r);
}
void update(int t,int s,int e,int c)
{
    if(s-1==e)return;
    if(segTree[t].color==c)return;
    int l=segTree[t].l;
    int r=segTree[t].r;
    if(l>=s&&r<=e)///当前操作的区间是所有操作区间的子区间
    {
        segTree[t].color=c;
        return;
    }
    if(segTree[t].color>=0)//存在颜色,往下更新
    {
///即把当前节点的颜色pushdown给子节点
///最坏情况一直到单点 然后单点保存信息
        segTree[lson(t)].color=segTree[t].color;
        segTree[rson(t)].color=segTree[t].color;
//        segTree[t].color=-2;//表示有多种颜色
    }
    int mid=(l+r)>>1;
///此处为区间更新 若为单点更新则无需考虑当前操作的区间和需要操作
///的区间之间的覆盖关系
    if(s>mid)update(rson(t),s,e,c);
///事实证明 mid应该属于右边
    else if(e<=mid)update(lson(t),s,e,c);
    else
    {
        update(lson(t),s,mid,c);
        update(rson(t),mid,e,c);
    }
    segTree[t].color=-2;///可以看做没有颜色和当前颜色这两种颜色?
}
int ans[N],tmp;
void cal(int t)
{
    if(segTree[t].color==-1)///没颜色 直接走
    {
        tmp=-1;
        return;
    }
    int c=segTree[t].color;
    if(c!=-2)///只有一种颜色
    {
        if(c!=tmp)
        {
            ans[c]++;
            tmp=c;
        }
        return;
    }
    if(segTree[t].l!=segTree[t].r)
    {
        cal(lson(t));
        cal(rson(t));
    }
}
int main()
{
    int n,m,x,y,id;
    n=N-5;
    while(cin>>m)
    {
        memset(ans,0,sizeof(ans));
        built(1,1,n);
        while(m--)
        {
            cin>>x>>y>>id;
            x++;///避免0的出现以及维护闭区间
            n=max(n,id);
            update(1,x,y,id);
        }
        tmp=-1;///最前面的前面是没有颜色的
        cal(1);
        for(int i=0;i<=n;i++)
        {
            if(ans[i])
                cout<<i<<" "<<ans[i]<<endl;
        }
        cout<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值