HDU 4343 贪心+倍增

Problem DescriptionThis is a very simple question. There are N intervals in number axis, and M queries just like “QUERY(a,b)” indicate asking the maximum number of the disjoint intervals between (a,b) .InputThere are several test cases. For each test case, the first line contains two integers N, M (0<N, M<=100000) as described above. In each following N lines, there are two integers indicate two endpoints of the i-th interval. Then come M lines and each line contains two integers indicating the endpoints of the i-th query.You can assume the left-endpoint is strictly less than the right-endpoint in each given interval and query and all these endpoints are between 0 and 1,000,000,000.OutputFor each query, you need to output the maximum number of the disjoint intervals in the asked interval in one line.Sample Input3 21 22 31 31 21 3Sample Output12AuthorHIT分析:首先不难看出要离散化,因为10^9很明显不好操作,所以考虑离散化。然后考虑贪心排序,把重的大区间都忽略掉,因为它一定是没有作用的,假设有两个重叠区间,我肯定选小的那个(贪心)。接着考虑枚举区间选就行了,但很明显要TLE,于是考虑倍增,f[i][j]表示从i坐标开始向右走2^j个区间的右端点的坐标,于是可以转移:f[i][j]=f[i][f[i][j-1][j-1];注意如果f[i][j-1]已经为最右端了,那f[i][j]也只能是最右端,这里要判断一下,不然f[i][j]就会被赋成0影响结果。最后跑一边倍增加起来就ok了;

# include <iostream>
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <cmath>
# include <vector>
# include <algorithm>
using namespace std;
inline int read()
{
    register int f=1,i=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
    return i*f;
}
vector<int>tmp;
struct node
{
	int l,r;
	friend bool operator < (const node &a,const node &b)
	{
		if(a.l==b.l) return a.r<b.r;
		return a.l<b.l;
	}
}q[100005];
int f[100005][28],size,n,m;
inline void LSH()
{
	sort(tmp.begin(),tmp.end());
	size=unique(tmp.begin(),tmp.end())-tmp.begin();tmp.resize(size);
	for(int i=0;i<n;++i)
	{
		q[i].l=lower_bound(tmp.begin(),tmp.end(),q[i].l)-tmp.begin();
		q[i].r=lower_bound(tmp.begin(),tmp.end(),q[i].r)-tmp.begin();
	}
}
inline int solve(int l,int r)
{
	int sum=0;
	for(int i=25;i>=0;--i)
	{
		if(f[l][i]<=r)
		{
			sum+=(1<<i);
			l=f[l][i];
		}
	}return sum;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		tmp.clear();
		for(int i=0;i<n;++i)
		{
			q[i].l=read(),q[i].r=read();
			tmp.push_back(q[i].l);
			tmp.push_back(q[i].r);
		}
		LSH();sort(q,q+n);
		int R=size,pos=n-1;
		for(int i=size-1;i>=0;--i)
		{
			while(pos>=0&&q[pos].l>=i) R=min(R,q[pos--].r);
			f[i][0]=R;//找到最近的右端点 
		}
		for(int j=1;j<=25;++j)
		    for(int i=0;i<size;++i)
		        if(f[i][j-1]<size) f[i][j]=f[f[i][j-1]][j-1];
		        else f[i][j]=size;//特判 
		int l,r;
		while(m--)
		{
		    l=read(),r=read();
			l=lower_bound(tmp.begin(),tmp.end(),l)-tmp.begin();
			r=upper_bound(tmp.begin(),tmp.end(),r)-tmp.begin()-1;
			if(l==size||r<=l||r<0) {puts("0");  continue;}  
			cout<<solve(l,r)<<endl;
		}
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值