poj 2528 Mayor's posters(动态线段树)

传送门:点击打开链接


题目大意:

给定一个 1 ~ 10000000 的区间,然后有N次操作(N <= 10000),第i次操作是将 l~r 区间覆盖为i。问最后一共有多少种有颜色。


解题思路:

一开始想到了离散化,但是想了一想感觉有点麻烦 然后就问专职搞数据结构的队友。然后他说了 动态线段树。思路如下:

定义一个ID。然后 根节点1表示掌管1-MAXN颜色的区间。然后每次都是动态的建树。当一个区间的左子区间还不存在时。建立它,并且记录下每个区间的左子区间和右子区间的ID.那么就可以搞了。

最后再用一个DFS 用SET来记录一共出现了多少种颜色。


注意:

当将一个区间的左子区间和右子区间被它更新之后时,一定要把他清零。

还有那个maxn。开始是未知的。


#include <set>
#include <cstdio>
using namespace std;
#define maxn 2000000
int lson[maxn],rson[maxn],color[maxn];
int cnt,root;
void build()
{
    cnt = 2;
    root = 1;
    lson[root] = 0;
    rson[root] = 0;
    color[root] = 0;
}

void pushdown(int id)
{
    if(!lson[id])
    {
        lson[id] = cnt++;
        lson[lson[id]] = 0;
        rson[lson[id]] = 0;
        color[lson[id]] = 0;
    }
    if(!rson[id])
    {
        rson[id] = cnt++;
        lson[rson[id]] = 0;
        rson[rson[id]] = 0;
        color[rson[id]] = 0;
    }
    if(color[id])
    {
        color[lson[id]] = color[id];
        color[rson[id]] = color[id];
        color[id] = 0;
    }
}

void op(int id,int ls,int rs,int l,int r,int c)
{
    if(ls >= l && rs <= r)
    {
        color[id] = c;
        return;
    }
    pushdown(id);
    int mid = (ls+rs)>>1;
    if(l <= mid) op(lson[id],ls,mid,l,r,c);
    if(mid < r) op(rson[id],mid+1,rs,l,r,c);

}
set<int > ans;

void dfs(int id)
{
    if(color[id])
    {
        ans.insert(color[id]);
        return;
    }
    if(lson[id]) dfs(lson[id]);
    if(rson[id]) dfs(rson[id]);
}


int main()
{
    int T;
    scanf("%d",&T);
    for(int ks = 1;ks <= T;ks++)
    {
        int n;
        scanf("%d",&n);
        ans.clear();
        build();
        for(int i = 1;i <= n;i++)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            op(root,1,10000000,l,r,i);
        }
        dfs(root);
        printf("%d\n",ans.size());
    }
    return 0;
}









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值