HDU 6183 线段树特殊处理

Color it

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 299    Accepted Submission(s): 60


Problem Description
Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B is painting. To prevent him from drawing messy painting, Little D asks you to write a program to maintain following operations. The specific format of these operations is as follows.

0  : clear all the points.

1   x   y   c  : add a point which color is  c  at point  (x,y) .

2   x   y1   y2  : count how many different colors in the square  (1,y1)  and  (x,y2) . That is to say, if there is a point  (a,b)  colored  c , that  1ax  and  y1by2 , then the color  c  should be counted.

3  : exit.
 

Input
The input contains many lines. 

Each line contains a operation. It may be '0', '1 x y c' (  1x,y106,0c50  ), '2 x y1 y2' ( 1x,y1,y2106  ) or '3'. 

x,y,c,y1,y2  are all integers.

Assume the last operation is 3 and it appears only once.

There are at most  150000  continuous operations of operation 1 and operation 2. 

There are at most  10  operation 0. 

 

Output
For each operation 2, output an integer means the answer .
 

Sample Input
  
  
0 1 1000000 1000000 50 1 1000000 999999 0 1 1000000 999999 0 1 1000000 1000000 49 2 1000000 1000000 1000000 2 1000000 1 1000000 0 1 1 1 1 2 1 1 2 1 1 2 2 2 1 1 2 1 2 2 2 2 1 1 2 1 2 1 3 2 2 1 2 2 10 1 2 2 10 2 2 0 1 1 1 1 2 1 1 1 1 1 2 1 2 1 1 2 1 2 2 1 2 1 1 2 1 2 1 1 2 2 1 2 2 10 1 2 2 10 2 2 3
 

Sample Output
  
  
2 3 1 2 2 3 3 1 1 1 1 1 1 1
 

题意:有多种操作

0是把点清空

1是在(x,y)上添加一个颜色为 c 的点

2是查询 横坐标1 到 x1,纵坐标 y1 到 y2 这块区域内颜色种数

3是结束程序

思路:

这个坐标的范围是 1 到 10^6 ,没法开那么大的线段树,所以我们可以对每种颜色建一个线段上,总共51种颜色,所以建立51棵线段树,由于横坐标固定了一个1,所以我们可以根据纵坐标建立线段树,用来维护对于颜色c,在纵坐标为 y1 的时候,最近的颜色的横坐标是多少,所以每次进一个点的时候,如果这个纵坐标已经有这种颜色了,就更新为横坐标最小的情况,因为确定了是从1开始,所以横坐标小的点总是能被取到。

做法表较特殊 ,用一个root[]数组存每种颜色的根,然后有一个 rson[] 和 lson[]数组,还有最重要的 v[]数组

Update的时候,进来一个节点,每次向左向右跑的时候就对应去到 lson 和 rson ,然后对于每种颜色在每个纵坐标下都会有一个编号,把那个编号作为线段树的编号,存在 v[]里面,存的是最小的横坐标。

查询的时候去查每种颜色,看是否在范围内就可以计数了。

#include<cstdio>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1100005
int cnt,lson[maxn * 3],rson[maxn * 3],v[maxn * 3];
int root[55],x1,y1,y2,flag;

void Update(int &rot,int l,int r,int x,int y){
	int mid = (l + r) >> 1;
	if(rot == 0){	//如果这个颜色在这个y坐标第一次出现,那么给它一个编号,并且把最近的x赋值 
		rot = ++cnt;
		v[rot] = x;
	}
	if(v[rot] > x){	// 如果这个颜色的 x 比记录的小,更新最近值 
		v[rot] = x;
	}
	if(l == r){
		return ;
	}
	if(y <= mid){
		Update(lson[rot],l,mid,x,y);
	}else{
		Update(rson[rot],mid + 1,r,x,y);
	}
} 
void Query(int rot,int l,int r){
	int mid = (l + r) >> 1;
	if(flag || rot == 0){
		return ;
	}
	if(l >= y1 && r <= y2){ //在y范围内且x在范围内 则表示该颜色存在 
		if(v[rot] <= x1)
			flag = 1;
		return ;
	}
	if(y1 <= mid)
		Query(lson[rot],l,mid);
	if(y2 >= mid + 1)
		Query(rson[rot],mid + 1,r);
}
int main(){
	int ans,opt,x,y,c;
	while(scanf("%d",&opt) != EOF){
		if(opt == 3)
			break;
		else if(opt == 0){
			for(int i = 1;i <= cnt;i++){
				lson[i] = rson[i] = 0;
			} 
			memset(root,0,sizeof(root));
			cnt = 0;
		}else if(opt == 1){
			scanf("%d %d %d",&x,&y,&c);
			Update(root[c],1,maxn,x,y);
		}else if(opt == 2){
			scanf("%d %d %d",&x1,&y1,&y2);
			ans = 0;
			for(int i = 0;i <= 50;i++){
				flag = 0;
				Query(root[i],1,maxn);
				ans += flag;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值