ZOJ - 1610 Count the Colors(区间更新)

本文介绍了一种使用区间更新实现颜色计数的方法。通过构建线段树,并利用map存储每个节点的颜色频次,实现了对线段上指定区间的颜色进行更新,并统计每种颜色出现的次数。文章详细解释了区间更新、标签传递及子节点合并的过程。

题意:给(a,b)线段染色为c,这种操作有n次!所有的点不超过8000。输出index的颜色能看见几次。
思路:区间更新。 所以我在结构体里直接上了map来存颜色,感觉有点蠢。。。但是好歹写出来了不是。。(只能这么安慰自己了)
因为有区间更新,所以也涉及到下推tag。这里要维护的要想到的一点就是,左儿子的尾和右儿子的头如果同色,这个算出现一次。其余的都很好想了,尤其是我这种弃疗写法。。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

#define itr map<int,int>::iterator

const int maxn = 8010;
const int inf = 0x3f3f3f3f;
int n;
int data[maxn][3];

struct node
{
    int l,r,tag,b,e;
    map<int,int> col;
}tr[maxn << 2];

void reset(int id,int l,int r)
{
    tr[id].l = l; tr[id].r = r; tr[id].tag = 0;
    tr[id].col.clear(); tr[id].e = tr[id].b = 0;
}
void build(int l,int r,int id)
{
    reset(id,l,r);
    if(l == r) return;
    int mid = l+r>>1;

    build(l,mid,id<<1);
    build(mid+1,r,id<<1|1);
}
void usetag(int id,int tag)
{
    tr[id].col.clear();
    tr[id].col.insert(pair<int ,int>(tag,1));
    tr[id].e = tr[id].b = tag;
    tr[id].tag = tag;
}

int push(int id,int tag)
{
    if(tag)
    {
        usetag(id<<1,tag);
        usetag(id<<1|1,tag);
        tr[id].tag = 0;
    }
    return 0;
}
void useson(int id)
{
    tr[id].col.clear();
    for(itr it = tr[id<<1].col.begin(); it != tr[id<<1].col.end(); it++)
    {
        int a = it->first, b = it->second;
        tr[id].col[a] = b;
    }
    for(itr it = tr[id<<1|1].col.begin(); it != tr[id<<1|1].col.end(); it++)
    {
        int a = it->first, b = it->second;
        tr[id].col[a] += b;
    }
    tr[id].b = tr[id<<1].b, tr[id].e = tr[id<<1|1].e;
    if(tr[id<<1].e == tr[id<<1|1].b)    tr[id].col[tr[id<<1].e] --;

}
void add(int al,int ar,int c,int id)
{
    int l = tr[id].l, r = tr[id].r;
    if(r <  al || l >  ar)    return;
    if(l >= al && r <= ar)
    {
        tr[id].tag = c;
        tr[id].col.clear();
        tr[id].col.insert(pair<int,int>(c,1));
        tr[id].b = tr[id].e = c;
        return;
    }
    push(id,tr[id].tag);

    add(al,ar,c,id<<1);
    add(al,ar,c,id<<1|1);

    useson(id);
}
int main()
{
    while(~scanf("%d",&n))
    {
        int r,a,b,c;
        r = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            a++;b;c++;
            data[i][0] = a,data[i][1] = b, data[i][2] = c;
            r = max(r,b);
        }
        build(1,r,1);
        for(int i = 0; i < n ; i++)
        {
            a = data[i][0], b = data[i][1], c = data[i][2];
            add(a,b,c,1);
        }
        itr it = tr[1].col.begin();
        for(; it != tr[1].col.end(); it++)
            printf("%d %d\n",it->first-1,it->second);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值