POJ --2528--Mayor's posters--离散线段树

没看题目又想看题解的童鞋请先把题目看了。

题目给的区间是1到一千万,询问却只有一万个,一千万的数组是开不下的,但是询问的区间比如给了一个,1--100的区间,中间2--99都是浪费掉的了不用的区间,这个题要是能发现这点就好办 了,这也应该是这题的难点,最后采取的办法是离散化的线段树,我最先使用的离散方法是使用的STL里面的SET和MAP,但是比较遗憾的是超时了,然后看了别人博客上的题解代码,借用了别人使用数组离散化线段树的办法,成功搞定

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define mmaxn 10000004
#define maxn 10003
#define M(a) memset((a),0,sizeof(a))
#define lc(c) ((c)<<1)
#define rc(c) ((c)<<1|1)
using namespace std;
struct node
{
	int l,r;
	int color;
}p[maxn<<2];
struct Command
{
	int l,r;
	int color;
}com[maxn];

bool  reg[mmaxn],vis[maxn];
int d[maxn<<1],ic,ans;
unsigned short int tal[mmaxn];
int n;

void init()
{
	M(reg);M(d);M(vis);
	ans=ic=0;
	int x, y;
	scanf("%d",&n);		//	下面开始离散区间的一一映射处理
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		if(!reg[x])
		{
			d[ic++]=x;
			reg[x]=1;
		}
		if(!reg[y])
		{
			d[ic++]=y;
			reg[y]=1;
		}
		com[i].l=x;
		com[i].r=y;
	}
	sort(d,d+ic);
	for(int i=0;i<ic;i++)
	tal[d[i]]=i+1;
	for(int i=0;i<n;i++)
	{
		com[i].l=tal[com[i].l];
		com[i].r=tal[com[i].r];
		com[i].color=i+1;
	}
	//搞定了,剩下的就是常规的线段树了
}

void build(int c,int x,int y)
{
	p[c].l=x;p[c].r=y;
	p[c].color=0;
	if(x==y)return;
	int m=(x+y)>>1;
	build(lc(c),x,m);
	build(rc(c),m+1,y);
}
void update(int c,int x,int y,int cl)
{
	int l=p[c].l,r=p[c].r;
	if(x==l&&r==y)
	{
		p[c].color=cl;
		return;
	}
	if(p[c].color>=0)
	{
		p[lc(c)].color=p[rc(c)].color=p[c].color;
		p[c].color=-1;
	}
	int m=(l+r)>>1;
	if(m>=y)update(lc(c),x,y,cl);
	else if (m<x)update(rc(c),x,y,cl);
	else
	{
		update(lc(c),x,m,cl);
		update(rc(c),m+1,y,cl);
	}
}
void dfs(int c)
{
	int u=p[c].color;
	if(u==0)return;
	if(p[c].color>0)
	{
		if(!vis[u])
		{
			vis[u]=1;
			ans++;
		}
		return;
	}
	dfs(lc(c));
	dfs(rc(c));
}
void solve()
{
	build(1,1,ic);
	for(int i=0;i<n;i++)
	{
		update(1,com[i].l,com[i].r,com[i].color);
	}
	dfs(1);
	printf("%d\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		init();
		solve();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值