poj2528 线段树染色+离散化

题意:

共n段,俩操作

修改:第i段【li,ri】染成颜色i

仅最后一次查询:最后的颜色数

li ri<=1e7  n<=1e4

思路:

POJ2777 颜色数只有30 维护颜色状态S就能A

这题颜色数那么多。。怎么办?

修改:维护颜色替换标记col:区间颜色(多个颜色则col为0),满足区间加法

显然叶子col不为0


为什么维护这个呢,我的理解是:

如果没有col那么就需要

暴力查询,修改到每个叶子。修改复杂度是nlogn

现在有了col之后。

修改:如果当前区间是修改子区间我就不用往下修改了

查询:如果我发现当前区间col不为0,那么我就不用往下搜了

对吧,从而减少复杂度

(这里查询只有一次,暴力到叶子也没关系)

(主要还是修改不用一定到叶子减了很多复杂度w)


查询:【1,1e7】之内搜

用vis【】防止统计颜色时重复计算


当然:这题如果在1e7之内搜会超时

这里有个常规套路叫离散化

即颜色段可以压缩,如下:

段1:1 10    段2:1 3     段3:6 10  显然答案是3段

1 1 1 1 1 1 1 1 1 1 

2 2 2       3 3 3 3 3

离散化: 1 10 1 3 6 10->1 3 6 10

即rk[1]=1,rk[2]=3,rk[3]=6,rk[4]=10

原来的3对应现在的2  原来的10对应现在的4....

所以离散化后现在变成下面了

段1:1 4      段2:1 2     段3:3 4

1 1 1 1

2 2 3 3

答案不对!怎么少了一段????

4 5被离散化合并掉了QAQ

这里只要我们对原先相邻大于1的插入1个数就好了

1 10 1 3 6 10->1 2 3 4 6 7 10

现在等价于

1 1 1 1 1 1 1

2 2 2    3 3 3 

【1,3】颜色2  【3,5】颜色1 【5,7】颜色3

耶!成功了=w=

离散化之后rk[1]=1 rk[3]=3 rk[5]=6,rk[7]=10

非重复有序数列,对于某一个数想找下标,二分即可

难度:0.9

91ms

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm> 
#include<iostream>
#include<vector>
#include<map>
using namespace std;
const int inf=0x3f3f3f;
struct point{
	int li;
	int ri;
};
bool vis[8*10005];
int rk[8*10005];
struct Stree
{
	int col;
} sts[16*10005]; //开4倍

point ps[10005];
void pushup(int root)
{
	if(sts[root<<1].col==sts[root<<1|1].col)
		sts[root].col=sts[root<<1].col;
}
void pushdown(int root)
{
	if(sts[root].col!=0)
	{
		sts[root<<1].col=sts[root].col;
		sts[root<<1|1].col=sts[root].col;
		sts[root].col=0;
	}
}
void build(int l,int r,int root)//根节点从1开始吧
{
	sts[root].col=0;//没了这句会WA,清空lazy跟val 
	if(l==r)//到达子节点
	{
		return;
	}
	else
	{
		int mid=(l+r)>>1;//(l+r)/2
		build(l,mid,root<<1);
		build(mid+1,r,root<<1|1);
	//	pushup(root);//更新本节点
	}
}
int query(int nowl,int nowr,int root)
{
	int ans=0;
	if(sts[root].col)
	{
		if(!vis[sts[root].col])
		{
			vis[sts[root].col]=1;
			return 1;
		}
		else return 0;
	}
	if(nowl==nowr)return 0;
	pushdown(root);
	int mid=(nowl+nowr)>>1;
	ans+=query(nowl,mid,root<<1);
	ans+=query(mid+1,nowr,root<<1|1);
	return ans;
}

void update(int nowl,int nowr,int ul,int ur,int root,int addval)//nowl,nowr 当前区间  ul,ur 需修改的区间 
{
	if(ul<=nowl&&ur>=nowr)//当前区间是修改区间的子区间
	{
		sts[root].col=addval;
		return ;
	}
	int mid=(nowl+nowr)>>1;
	pushdown(root);//避难 
	if(ul<=mid) update(nowl,mid,ul,ur,root<<1,addval);//左子树与修改区间有交集
	if(ur>mid)  update(mid+1,nowr,ul,ur,root<<1|1,addval);
	pushup(root);
	return ;
}
void op();
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(vis,0,sizeof(vis));
		int n;int m=0;
		scanf("%d",&n);
		for(int i=1; i<=n; i++)
		{
			scanf("%d %d",&ps[i].li,&ps[i].ri);
			rk[++m]=ps[i].li;//离散化 
			rk[++m]=ps[i].ri;//离散化 
		}
//		for(int i=1;i<=m;i++)
//			printf("rkm:%d\n",rk[i]);

		sort(rk+1,rk+m+1);//离散化 先排序 
		int tot=1;//去重,插入要重新定下标 
		for(int i=2;i<=m;i++)
			if(rk[i]!=rk[i-1])rk[++tot]=rk[i];
		
		
		for(int i=tot;i>=2;i--)//插入 当区间长度>=2要插入一个中间值 
			if(rk[i]!=rk[i-1]+1)rk[++tot]= rk[i]-1;
		sort(rk+1,rk+tot+1);
	//	printf("tot:%d\n",tot);
		build(1,tot,1);
	//	op();
		for(int i=1;i<=n;i++)
		{
			int l=lower_bound(rk+1,rk+1+tot,ps[i].li)-rk;//找出第一个大于等于原下标的新下标
			int r=lower_bound(rk+1,rk+1+tot,ps[i].ri)-rk;	
			update(1,tot,l,r,1,i); 
			//op();
		} 
	//	op();
		int ans=query(1,tot,1);
		printf("%d\n",ans);
	 
	}

}



void sp(int t)
{
	for(int i=1;i<=t;i++)
	printf(" ");
}
void op()
{
	int pow2[10]={1,2,4,8,16,32};int n=16;
	printf("\n///\n");
	for(int i=1; i<=31; i++)
	{
		if(i==pow2[0])sp(15);
		if(i==pow2[1])sp(7);
		if(i==pow2[2])sp(3);
		if(i==pow2[3])sp(1);
		if(i>pow2[1]&&i<pow2[2])sp(15);
		if(i>pow2[2]&&i<pow2[3])sp(7);
		if(i>pow2[3]&&i<pow2[4])sp(3);
		if(i>pow2[4]&&i<pow2[5])sp(1);
		printf("%d",sts[i].col);
		if((i==pow2[1]-1)||(i==pow2[2]-1)||(i==pow2[3]-1)||(i==pow2[4]-1))
			printf("\n");
	}
	printf("\n///\n");
}











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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值