hdu6183 Color it(动态开点线段树/cdq分治)

该博客讨论了一种二维平面上的颜色点管理问题,涉及四种操作:清除所有点、添加点、统计矩形区域内点的颜色数以及退出程序。文章提供了两种解决方案:一种使用动态开点的线段树,另一种采用CDQ分治策略。这两种方法在时间和空间复杂度上有不同的权衡。

题目

二维平面,读入若干行,每一行对应一次操作,操作分4种:

0:清掉平面内所有点

1 x y c(1<=x<=1e6,1<=y<=1e6,0<=c<=50):在(x,y)加入一个颜色为c的点,点重合时同时存在

2 x y1 y2(1<=x<=1e6,1<=y1<=y2<=1e6):统计以(1,y1)左下角以(x,y2)右上角这个矩形内点的颜色数

3:退出程序

数据保证只有最后一行是3操作,连续的1或2操作只有最多15W个(即每逢15W就清零一次),0操作最多只有10次

思路来源

https://www.cnblogs.com/lipeiyi520/p/10961683.html

题解1

首先考虑每次查询的左下角都是1,

画出图来,发现是一个以y轴为底边的矩形,

则其中的点的x值越小越容易被包含在询问里,

所以按y轴建线段树,维护x的最小值,

每个颜色开一棵1e6的线段树,这样时间是可行的O(10*1e5*log1e6),但是空间O(50*1e6*4)不大行

所以51个颜色对应的线段树都写成动态开点的,

颜色i对应的树的树根是root[i],有点像主席树那个写法

查询即对每个颜色暴力[y1,y2]内的x的最小值是不是小于当前询问的x即可

代码1

#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
int op,u,v,w,root[55],cnt;
//主席树动态开点思想 
struct node{
	int l,r,mn;
	node():l(0),r(0),mn(N){}
}e[N*4];
void newnode(int &p){
	p=++cnt;
	e[p].l=e[p].r=0;
	e[p].mn=N;
}
void upd(int &p,int l,int r,int x,int v){
	if(!p){
		newnode(p);
	}
	if(l==r){
		e[p].mn=min(e[p].mn,v);
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid)upd(e[p].l,l,mid,x,v);
	else upd(e[p].r,mid+1,r,x,v);
	e[p].mn=min(e[e[p].l].mn,e[e[p].r].mn);	
}
bool ask(int p,int l,int r,int ql,int qr,int v){
	if(ql>qr)return 0;
	if(!p)return 0;
	if(ql<=l&&r<=qr){
		return e[p].mn<=v;
	}
	int mid=(l+r)/2;
	if(ql<=mid && ask(e[p].l,l,mid,ql,qr,v))return 1;
	if(qr>mid && ask(e[p].r,mid+1,r,ql,qr,v))return 1;
	return 0; 
}
int main(){
	while(~scanf("%d",&op) && op!=3){
		if(op==0){
			for(int i=0;i<=50;++i){
				root[i]=0;
			}
			cnt=0;	
		}
		else if(op==1){
			scanf("%d%d%d",&u,&v,&w);
			upd(root[w],1,N,v,u);//按y轴建 维护x的最小值 
		}
		else if(op==2){
			scanf("%d%d%d",&u,&v,&w);
			int ans=0;
			for(int i=0;i<=50;++i){
				ans+=ask(root[i],1,N,v,w,u);
			}
			printf("%d\n",ans);
		}
	} 
	return 0;
} 

题解2

考虑cdq分治,清零/退出的时候再回答答案,把询问离线,

这样要处理时间序上1的修改对2的回答的影响,

所以是一个类似(时间,x,y)的三维偏序问题,默认时间增序排序

归并的时候考虑[l,mid]对[mid+1,r]的影响,

其实可以忽略[l,mid]内的查询操作,但为了方便排序写法上让修改更靠前

优先处理[l,mid]的修改操作①,同是修改操作的显然x更小的应先遍历②,同是查询操作的无所谓③

①、②、③确定了回溯的时候[l,r]的排序方式,归并的时候就按x增序归并即可

查询的时候,由于x小的都已经插入BIT,

此时,查询[y1,y2]内被插入的点的种类数,51种,这个可以1<<51二进制取或来维护

cdq时间是动态开点线段树的一半你敢信

代码2

代码待补

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值