做作业-贪心-并查集

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\n",a[i].y); break;}
    }
}

猜你喜欢

转载自www.cnblogs.com/wuwendongxi/p/13365502.html