Description
暑假到了,小明的老师们布置了一系列共N个作业给大家做。由于作业的相关性,考虑到同学们假期要去社会实践,同学们只需做完连续的一段作业即可。每个作业有俩个参数,需要的时间长度和难度系数。老师怕同学们太偷懒,要求连续的一段作业总时间必须不小于指定的M。小明是特别害怕做难题,因此想请学编程的你帮他选出一段作业,既能满足老师要求,其最大难度作业的难度又最小。
Input
第一行:两个空格分开的数N(1≤N≤100,000) 和M(1≤M≤10^18);
以下N行:两个空格分开的数Ti,Si,表示第i个作业的长度和难度(1≤Ti≤109,1≤Si≤109)
Output
输出仅一个整数表示选出的这段作业的最大难度。
Sample Input
5 10
4 10
6 15
3 5
4 9
3 6
Sample Output
9
Hint
【数据范围】
40%的数据满足,N<=1000;
100%的数据满足,N<=100,000
思路
- 贪心,并查集合并。将作业按难度升序排列,优先选难度低的作业。选的过程中合并原始顺序相邻的作业(相邻的区间成一个连通块/集合),当某次合并后,区间总和大于M,此时的难度即为答案。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 100005
using namespace std;
int n,f[maxn],flag[maxn];
long long m,s[maxn];
struct fdfdfd{int x,y,id;}a[maxn];
bool cmp(fdfdfd a,fdfdfd b){return a.y<b.y;}
int getfa(int x){return f[x]==x?x:f[x]=getfa(f[x]);}
void merge(int x,int y)
{
x=getfa(x);y=getfa(y);
s[x]+=s[y];
f[y]=x;
}
int main()
{
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;++i) scanf("%d%d",&a[i].x,&a[i].y),a[i].id=f[i]=i,s[i]=a[i].x;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;++i)
{
int id=a[i].id; flag[id]=1;
if(flag[id-1]) merge(id,id-1);
if(flag[id+1]) merge(id,id+1);
if(s[getfa(id)]>=m) {printf("%d
",a[i].y); break;}
}
}