【HDU - 6183】Color it(CDQ分治 或 动态开点线段树)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/89240744

题干:

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. 

00 : clear all the points. 

11 xx yy cc : add a point which color is cc at point (x,y)(x,y). 

22 xx y1y1 y2y2 : count how many different colors in the square (1,y1)(1,y1) and (x,y2)(x,y2). That is to say, if there is a point (a,b)(a,b) colored cc, that 1≤a≤x1≤a≤x and y1≤b≤y2y1≤b≤y2, then the color cc should be counted. 

33 : exit. 

Input

The input contains many lines. 

Each line contains a operation. It may be '0', '1 x y c' ( 1≤x,y≤106,0≤c≤501≤x,y≤106,0≤c≤50 ), '2 x y1 y2' (1≤x,y1,y2≤1061≤x,y1,y2≤106 ) or '3'. 

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

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

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

There are at most 1010 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

题目大意:

解题报告:

直接51颗线段树,按照y轴建树,然后维护x的最小值。但是直接建树会mle,所以考虑动态开点。注意不要手滑写错emmm。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 1e6 + 5;
const int INF = 0x3f3f3f3f;
struct TREE {
	int l,r;
	int minn; 
} tree[MAX<<2];
int root[555],tot,flag;

void pushup(int rt) {
	int L = tree[rt].l,R = tree[rt].r;
	tree[rt].minn =  min(tree[L].minn,tree[R].minn);
}
void update(int &rt,int l,int r,int tar,int x) {
	if(rt == 0) {
		rt = ++tot;
		tree[rt].l = tree[rt].r = 0;
		tree[rt].minn = x;
	}
	if(l == r) {
		tree[rt].minn = min(tree[rt].minn,x);
		return;
	}
	int m = (l+r)>>1;
	if(tar <= m) update(tree[rt].l,l,m,tar,x);
	else update(tree[rt].r,m+1,r,tar,x);
	pushup(rt);
}
void query(int rt,int l,int r,int pl,int pr,int x) {
	if(flag || !rt) return ;
	if(pl <= l && pr >= r) {
		if(tree[rt].minn <= x) flag = 1;
		return ;
	}
	int m = (l+r)>>1;
	if(pl <= m) query(tree[rt].l,l,m,pl,pr,x);
	if(pr > m) query(tree[rt].r,m+1,r,pl,pr,x);
}
int main()
{
	int op;
	tree[0].l = tree[0].r = 0;
	tree[0].minn = INF;
	while(scanf("%d",&op)) {
		if(op == 3) break;
		if(op == 0) {
			for(int i = 0; i<=50; i++) root[i] =0;
			tot=0;
		}
		if(op == 1) {
			int x,y,c;
			scanf("%d%d%d",&x,&y,&c);
			update(root[c],1,1000000,y,x);
		}
		if(op == 2) {
			int x,y1,y2,ans = 0;
			scanf("%d%d%d",&x,&y1,&y2);
			for(int i = 0; i<=50; i++) {
				flag = 0;
				query(root[i],1,1000000,y1,y2,x);
				ans += flag;
			}
			printf("%d\n",ans);
		}		
	}
	return 0 ;
}

总结:

还有一个坑啊,

    tree[0].l = tree[0].r = 0;
    tree[0].minn = INF;

这两步必须有,因为这里是单点更新,所以update里面的if和else只进去一个,另一边没有开点。假设进入了l并且开点了l,那么tree[rt].r=0,所以你pushup的时候直接从右孩子取值直接就变成tree[0].minn了,,所以直接就成0了,所以为了避免这一状态发生,我们要把0这个节点设置成非法节点,也就是不影响结果就可以,所以我们把tree[0].minn=INF就可以了。

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/89240744