POJ_1769_动态规划+线段树

今天刷了三个题,爽爆了


题意:

有一种输出n个数字最大值的数据结构,它的内部是m个小装置组成的,第i个小装置可以将l[i]到r[i]范围内的数字升序排列。小装置顺序固定,过程必须一个一个进行。有时减少一些小装置,这个数据结构仍能正常运作,请问最少有几个小装置。



Input

The first line of the input contains two integers n and m (2 <= n <= 50000, 1 <= m <= 500000) separated by a single space. Integer n is the number of inputs and integer m is the number of sorters in the pipeline. The initial sequence of sorters is described in the next m lines. The k-th of these lines contains the parameters of the k-th sorter: two integers ik and jk (1 <= ik < jk <= n) separated by a single space.

Output

The output consists of only one line containing an integer equal to the length of the shortest subsequence of the initial sequence of sorters still producing correct results for all possible data.


首先是动态规划,dp[i]表示把最大值从1位置搞到第i个小装置结尾最少需要多少个小装置,这样的话,从小到大遍历所有装置,每次查询当前装置之前的装置区间和当前装置相交的装置,更新dp就可以了。

那么问题就来了,装置有m个,这样O(m^2)的算法绝壁TLE。

用线段树来维护区间最小dp值信息,每个点维护ll到rr范围内的dp最小是多少。没算完一个新的小装置只需把它的dp值插到树上就行了。

然后TLE了,这里有个小贪心,每次更新不需要更新区间信息,因为对每个区间,r点之前的信息对更新之后的装置dp没有贡献,因为要努力使最大值向右移,因此单点更新即可。虽然不知道是不是我的lazy标记写挫了。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxn 50010
#define mxm 500010
#define inf 0x3f3f3f3f
int n,m;
int dp[mxm];
struct node{
	int ll,rr;
	int minn;
};
class segment_tree{
private:
	node nd[mxm<<2];
public:
	void build(int l,int r,int id){
		nd[id].ll=l;
		nd[id].rr=r;
		nd[id].minn=inf;
		if(l==r)	return;
		int m=(l+r)>>1;
		int ls=id<<1,rs=ls|1;
		build(l,m,ls);
		build(m+1,r,rs);
	}
	int find(int l,int r,int id){
		if(nd[id].ll==l&&nd[id].rr==r)	return nd[id].minn;
		int m=(nd[id].ll+nd[id].rr)>>1;
		int ls=id<<1,rs=ls|1;
		if(r<=m)	return find(l,r,ls);
		else if(l>m)	return find(l,r,rs);
		else	return min(find(l,m,ls),find(m+1,r,rs));
	}
	void insert(int loc,int x,int id){
		nd[id].minn=min(nd[id].minn,x);
		int m=(nd[id].ll+nd[id].rr)>>1;
		int ls=id<<1,rs=ls|1;
		if(nd[id].ll==nd[id].rr)	return;
		if(loc<=m)	insert(loc,x,ls);
		else 	insert(loc,x,rs);
	}
}Tree;
int main(){
	memset(dp,0x3f,sizeof(dp));
	scanf("%d%d",&n,&m);
	int a,b,ans=inf;
	Tree.build(1,n,1);
	for(int i=0;i<m;++i){
		scanf("%d%d",&a,&b);
		if(a==1)	dp[i]=1;
		else dp[i]=inf;
		int tem=Tree.find(a,b,1);
		dp[i]=min(dp[i],tem+1);
		Tree.insert(b,dp[i],1);
		if(b==n)	ans=min(ans,dp[i]);
	}
	printf("%d\n",ans);
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值