POJ 2528 Mayor's posters(线段树)

本文介绍了一种使用线段树数据结构解决墙面涂色问题的方法。通过离散化端点并构建线段树,逆序遍历涂色操作,标记被涂色的节点,最终统计未被覆盖的颜色种类,实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

每次往墙上li - ri的范围涂色,每次涂得颜色不一样,后涂的会覆盖前面的,求最终墙上有几种颜色

思路:

将所有端点离散化建立一课线段树,树上每个节点代表这个节点覆盖的范围以及是否被涂色,逆序将所有序列覆盖线段树上的节点,若有节点是空的,则代表最终有这个颜色,标记覆盖后的节点,若没有可以覆盖的节点,则此颜色最终不会出现

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

#define Clr(x) memset(x,0,sizeof(x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define INF 0x33333333
#define LP(x,y) for(int i = x; i < y; i++)
#define LP2(x,y) for(int j = x; j >= y; j--) 

using namespace std;
typedef long long LL;
//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int maxn = 100000;
int t,n,ans;
struct node{
	int l,r;
	bool covered;
}p[maxn<<1];
bool lazy[maxn<<1];
int l[maxn],r[maxn];
vector<int> v;
void pushup(int rt)
{
	p[rt].l = p[rt<<1].l;
	p[rt].r = p[rt<<1|1].r;
	p[rt].covered = p[rt<<1].covered && p[rt<<1|1].covered;
}
void pushdown(int rt) 
{
	if(lazy[rt])
	{
		lazy[rt<<1] = true;
		lazy[rt<<1|1] = true;
		p[rt<<1].covered = true;
		p[rt<<1|1].covered = true;
	}
}
void build(int l,int r,int rt)
{
	if(l == r)
	{
		p[rt].l = v[l-1];
		p[rt].r = v[l-1];
		p[rt].covered = false;
		return;
	}
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	pushup(rt);
}
int post(int L,int R,int rt)
{
	if(p[rt].l >= L && p[rt].r <= R)
	{
		if(p[rt].covered) return 0;		//已被覆盖 
		else							//可覆盖节点 
		{
			p[rt].covered = true;
			lazy[rt] = true;
			return 1;
		}		
	}
	pushdown(rt);
	int res = 0;
	if(L <= p[rt<<1].r && !p[rt<<1].covered) res = max(res,post(L,R,rt<<1));
	if(R >= p[rt<<1|1].l && !p[rt<<1|1].covered) res = max(res,post(L,R,rt<<1|1));
	pushup(rt);
	return res;
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		v.clear();
		Clr(lazy);
		Clr(l);
		Clr(r);
		scanf("%d",&n);
		LP(0,n)
		{
			scanf("%d%d",&l[i],&r[i]);
			v.push_back(l[i]);
			v.push_back(r[i]);
		}
		sort(v.begin(),v.end());
		int num = unique(v.begin(),v.end()) - v.begin();	//所有端点数量 
		build(1,num,1);					//建树 
		int ans = 0;
		LP2(n-1,0) ans += post(l[j],r[j],1);
			
		printf("%d\n",ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值