poj 2528

题目

这道题就是以前还不会的区间覆盖然后查询的问题(这道题是按顺序覆盖,还比较好做了)。

其实相对于普通的线段树,就是没有向上合并的过程而已(因为没什么用)。

查询的时候就是值域全部查询,一个一个点往下找,就可以了,根本就没有太复杂的东西。

当然这题还要离散化,跟普通离散化不大一样,对于距离大于1的点,我们还得插入一个点,否则会出现一些错误(其他博客也有说,或者就是大家想的那些)。

要注意的是,这类题在初始化的时候,线段树所有点的初始值必须都一样,否则下传的时候会发现各种奇葩错误。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
#include<cmath>
#include<map> 
#include<string>
#include<queue>
#include<stack> 
#include<bitset>
#include<list>
#include<set>
#include<utility>
#include<iomanip>
#define IO ios::sync_with_stdio(false)
#define eps 1e-7
//#define int long long
using namespace std;
struct node
{
	int l,r,sum;
}t[40005*4];
int li[40005],ri[40005],vis[40005],lis1[40005],len1,len2,n,tt,len3,ans;
void push_down(int rt)
{
	if(t[rt].sum!=0)
	{
		t[rt*2].sum=t[rt].sum;
		t[rt*2+1].sum=t[rt].sum;
		t[rt].sum=0;
	}
}
void build(int rt,int l,int r)
{
	t[rt].l=l,t[rt].r=r;
	if(l==r)
	{
		t[rt].sum=0;
		return;
	}
	int mid=l+r>>1;
	build(rt*2,l,mid);
	build(rt*2+1,mid+1,r);
	//t[rt].sum=-1;
}
void upd(int rt,int l,int r,int v)
{
	if(l<=t[rt].l&&r>=t[rt].r)
	{
		t[rt].sum=v;
		return;
	}
	push_down(rt);
	int mid=t[rt].l+t[rt].r>>1;
	if(l<=mid)
	{
		upd(rt*2,l,r,v);
	}
	if(r>mid)
	{
		upd(rt*2+1,l,r,v);
	}
}
void ask(int rt,int l,int r)
{
	if(t[rt].sum!=0)
	{
		if(!vis[t[rt].sum])
		{
			vis[t[rt].sum]=1;
			//cout<<t[rt].l<<" "<<t[rt].r<<" "<<t[rt].sum<<endl;
			ans++;
		}
		return;
	}
	if(l==r)return;
	int mid=l+r>>1;
	ask(rt*2,l,mid);
	ask(rt*2+1,mid+1,r);
}
int main()
{
	scanf("%d",&tt);
	while(tt--)
	{
		memset(t,0,sizeof(t));
		memset(vis,0,sizeof(vis));
		ans=len3=len1=len2=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d %d",&li[i],&ri[i]);
			lis1[++len1]=li[i];
			lis1[++len1]=ri[i];
		}
		sort(lis1+1,lis1+len1+1);
		len2=unique(lis1+1,lis1+len1+1)-(lis1+1);
		len3=len2;
		for(int i=2;i<=len2;i++)
		{
			if(lis1[i]-lis1[i-1]>1)
			{
				lis1[++len3]=lis1[i-1]+1;
			}
		}
		sort(lis1+1,lis1+len3+1);
		build(1,1,len3);
		//cout<<len3<<endl;
		/*for(int i=1;i<=len3;i++)
		{
			cout<<lis1[i]<<endl;
		}*/
		for(int i=1;i<=n;i++)
		{
			int ll=lower_bound(lis1+1,lis1+len3+1,li[i])-lis1;
			int rr=lower_bound(lis1+1,lis1+len3+1,ri[i])-lis1;
			//cout<<"i:"<<i<<" "<<ll<<" "<<rr<<" "<<li[i]<<" "<<ri[i]<<" "<<endl;
			upd(1,ll,rr,i);
		}
		ask(1,1,len3);
		printf("%d\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值