Count the colors

本文介绍了一种使用线段树解决颜色查询问题的方法。通过构建线段树,并实现插入和查询操作来统计不同颜色出现的段数。文章提供了完整的代码实现。

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

Count the colors

查询某种颜色出现的段数,用线段树解。首次用线段树解该类题目。对于查询的时候,只不过需要注意,每次标记一下访问过的区间,它的颜色是不是和现在正在查询的区间的颜色视相同的,如果是则不比统计,因为它们是连续的一段,否则的话就要累加,然后记录该点的颜色。在递归的时候,总是先后查询相邻区间的颜色的值,故而采用此种方式能解决对应的线段的连续性问题。然后需要注意线段的最小区间长度是1,所以元线段为(l,l+1)。代码如下:

#include<stdio.h>
#include<string.h>

#define MAXN 8000

struct Node{
	int l ;
	int r ;
	int color ;
}node[MAXN*4] ;

int n ;
int temp ;
int ncount[MAXN+5] ;

void build(int l , int r , int c){
	
	node[c].l = l ;
	node[c].r = r ;
	node[c].color = -1 ;
	
	if(l + 1 == r){
		return ;
	}
	
	build(l , (l+r)/2 , c*2) ;
	build((l+r)/2 , r , c*2+1) ;
}

void pushdown(int c){
	if(node[c].color < 0){
		return ;
	}
	
	node[c*2].color = node[c].color ;
	node[c*2+1].color = node[c].color ;
	node[c].color = -2 ;
}

void insert(int l , int r , int color , int c){
	if(l==r)
		return ;
	
	if(node[c].color == color)
		return ;
		
	if(l == node[c].l && r == node[c].r ){
		node[c].color = color ;
		return ;
	}	
	
	pushdown(c) ;
	
	int mid = (node[c].l + node[c].r)/2 ;
	
	if(mid >= r){
		insert(l , r , color , c*2) ;
	}
	else if(mid<=l){
		insert(l , r , color , c*2+1) ;
	}
	else {
		insert(l , mid , color , c*2) ;
		insert(mid , r , color , c*2+1) ;
	}
}

void query(int c){
	//区间为单一颜色
	if(node[c].color >= 0 ){
		if(node[c].color != temp){
			ncount[node[c].color] ++ ;
			temp = node[c].color ;
		}
		return ;
	}
	//区间长度不是元线段
	if(node[c].l + 1 != node[c].r){
		query(c*2) ;
		query(c*2+1) ;
		return ;
	}			
	//区间未着色
	else
		temp = -1 ;
	
}

bool init(){
	if(scanf("%d" , &n)==EOF){
		return 0 ;
	}
	
	int i ;
	int p ;
	int q ;
	int w ;
	build(0 , 8000 , 1) ;
	for(i = 0 ; i < n ; i ++){
		scanf("%d %d %d" , &p ,&q ,&w) ;
		insert(p , q , w , 1) ;
	}
	return 1 ;
}

void work(){
	
	memset(ncount , 0 , sizeof(ncount)) ;
	temp = -1 ;
	
	query(1) ;
	
	for(int i = 0 ; i < 8000 ; i ++){
		if(ncount[i]){
			printf("%d %d\n" , i , ncount[i]) ;
		}
	}
}

int main(){
	
	while(init()){
		work() ;
		printf("\n") ;
	}
	return 0 ;
}


07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值