POJ2777:线段树(颜色更新)

本文详细解析了POJ2777题目的解题思路,通过线段树实现区间颜色更新与查询,介绍了push_down、push_up操作,并提供了完整的代码示例。同时,对比了状态压缩方法的优劣。

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

POJ2777

题解:

花了半天终于A了这一题,网上看了很多题解,代码风格和思路和常规的线段树风格都不一样,所以不想学。但最后终于找到合适自己的了。

一个记录颜色,一个lazy标志。多种颜色就用-1表示。然后就是push_down,push_up操作。详见代码,应该很好懂

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int const N = 100000 + 10;
int const T = 30 + 5;
int n,t,m;
bool vis[T];
struct Node
{
	int l,r,col,lazy;
	void updata(int val){
		col = val;
		lazy = val;
	}
}node[N<<2];
void push_up(int id){
	if(node[id>>1].col == -1 || node[id<<1|1].col == -1)
		node[id].col = -1;
	else if(node[id<<1].col == node[id<<1|1].col)
		node[id].col = node[id<<1].col;
	else node[id].col = -1;
}
void push_down(int id){
	int lazy = node[id].lazy;
	if(lazy){
		node[id<<1].updata(lazy);
		node[id<<1|1].updata(lazy);
		node[id].lazy = 0;
	}
}
void build(int id,int l,int r){
	node[id].l = l,node[id].r = r;
	node[id].lazy = 0;
	if(l == r){
		node[id].col = 1;
		return;
	}
	else{
		int mid = (l + r) >> 1;
		build(id<<1,l,mid);
		build(id<<1|1,mid+1,r); 
		push_up(id);
	}
}
void updata(int id,int L,int R,int k){     //将区间[L,R]的颜色更新为k
	int l = node[id].l,r = node[id].r;
	if(L <=l && r <= R){
		node[id].updata(k);
		return;
	}
	push_down(id);
	int mid = (l + r) >> 1;
	if(L <= mid)	updata(id<<1,L,R,k);
	if(mid < R)		updata(id<<1|1,L,R,k);
	push_up(id);
}
void query(int id,int L,int R){
	int l = node[id].l,r = node[id].r;
	if(node[id].col > 0){
		vis[node[id].col] = true;
		return;
	}
	push_down(id);
	int mid = (l + r) >> 1;
	if(L <= mid)query(id<<1,L,R);
	if(mid < R)query(id<<1|1,L,R);
}
int main(){
	scanf("%d%d%d",&n,&t,&m);
	build(1,1,n);
	char k;
	int x,y,z;
	for(int i=1;i<=m;i++){
		scanf(" %c",&k);
		if(k == 'C'){
			scanf("%d%d%d",&x,&y,&z);
			updata(1,min(x,y),max(x,y),z);
		}else{
			scanf("%d%d",&x,&y);
			memset(vis,false,sizeof(vis));
			query(1,min(x,y),max(x,y));
			int ans = 0;
			for(int i=1;i<=30;i++)
				if(vis[i])	ans++;
			printf("%d\n",ans);
		}
	}
	return 0;
}

另解:状态压缩

原本觉得上面的方法特别好,但是做到CF620E,就TLE了。

所以就又学习了状态压缩的方法。很有收获,代码和上面的类似。

详细请见:https://blog.csdn.net/sg_siqing/article/details/12209027

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int const N = 100000 + 10;
int const T = 30 + 5;
int n,t,m;
struct Node
{
	int l,r,col,lazy;
	void updata(int val){
		col = lazy = val;
	}
}node[N<<2];
void push_up(int id){
	node[id].col = node[id<<1].col | node[id<<1|1].col;
}
void push_down(int id){
	int lazy = node[id].lazy;
	if(lazy){
		node[id<<1].updata(lazy);
		node[id<<1|1].updata(lazy);
		node[id].lazy = 0;
	}
}
int lowbit(int x){return x&-x;}
int count(int t){
	int c = 0;
	while(t){
		c++;
		t -= lowbit(t);
	}
	return c;
}
void build(int id,int l,int r){
	node[id].l = l,node[id].r = r;
	node[id].lazy = 0;
	if(l == r){
		node[id].col = 2;
		return;
	}
	else{
		int mid = (l + r) >> 1;
		build(id<<1,l,mid);
		build(id<<1|1,mid+1,r); 
		push_up(id);
	}
}
void updata(int id,int L,int R,int k){     //将区间[L,R]的颜色更新为k
	int l = node[id].l,r = node[id].r;
	if(L <=l && r <= R){
		node[id].updata(k);
		return;
	}
	push_down(id);
	int mid = (l + r) >> 1;
	if(L <= mid)	updata(id<<1,L,R,k);
	if(mid < R)		updata(id<<1|1,L,R,k);
	push_up(id);
}
int query(int id,int L,int R){
	int l = node[id].l,r = node[id].r;
	if(L <= l && r <= R)	return node[id].col;
	push_down(id);
	int res = 0;
	int mid = (l + r) >> 1;
	if(L <= mid)	res = query(id<<1,L,R);
	if(mid < R)		res |= query(id<<1|1,L,R);
	return res;
}
int main(){
	scanf("%d%d%d",&n,&t,&m);
	build(1,1,n);
	char k;
	int x,y,z;
	for(int i=1;i<=m;i++){
		scanf(" %c",&k);
		if(k == 'C'){
			scanf("%d%d%d",&x,&y,&z);
			updata(1,min(x,y),max(x,y),1<<z);
		}else{
			scanf("%d%d",&x,&y);
			printf("%d\n",count(query(1,min(x,y),max(x,y))));
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值