Code Forces 589G Hiring(树状数组)

Hiring

time limit per test:4 seconds

memory limit per test:512 megabytes

input:standard input

output:standard output

The head of human resources department decided to hire a new employee. He created a test exercise for candidates which should be accomplished in at most m working days. Each candidate has to pass this test exercise. During the j-th day a candidate is allowed to be in the office for at most tj units of time.

Overall, n candidates decided to apply for the job and sent out their resumes. Based on data received the head has defined two parameters describing every candidate: di and ri. The parameter di is the time to get prepared for work which the i-th candidate spends each morning. This time doesn't depend on day. The parameter ri is the total working time needed for the i-th candidate to accomplish the whole test exercise.

Thus the time spent in the office in the j-th day consists of di units of time to get prepared and some units of time to proceed with the exercise. A candidate can skip entire working day and do not come to the office. Obviously in this case he doesn't spend di units of time to prepare.

To complete the exercise a candidate should spend exactly ri units of time working on the exercise (time to prepare is not counted here).

Find out for each candidate what is the earliest possible day when he can fully accomplish the test exercise. It is allowed to skip working days, but if candidate works during a day then he must spend di units of time to prepare for work before he starts progressing on the exercise.

Input

The first line contains two integer numbers n,  m (1 ≤ n,  m ≤ 2·105) — the number of candidates and the maximum number of working days to do the test exercise.

The second line contains m integer numbers t1, t2, ..., tm (1 ≤ tj ≤ 106) — the durations of working days in time units.

The following n lines contain two integers each: di,  ri (0 ≤ di ≤ 106,  1 ≤ ri ≤ 106) — how much time in the beginning of a day is required for i-th candidate before he starts his work on the test exercise and how much time it is needed for him to accomplish this task.

Output

Output a sequence of n integer numbers b1, b2, ..., bn, where bi is the earliest day when the i-th candidate can finish the test exercise.

In case the i-th candidate cannot finish the test exercise in m days output bi = 0.

Days in this problem are numbered from 1 to m in the order they are given in the input.

Examples
Input
3 3
4 2 5
1 3
2 5
3 4
Output
1 3 0



        果然三个小时对于我们来说还是不够把中档以下的题目做完……

        此题其实也是一道不太难想到的一个中档题。大致题意:给你n个人,然后每一个人有每天工作的准备时间和他们的这几天要工作的总时长。然后他们只有m天的时间完成这个总时长,而且每天有限制的工作时间ti。对于这个工作准备时间,要计算在每天的工作时间以内。对于这点,比如说某个人准备时间为2,然后某天时间限制为5,那么有效工作时间就是3,如果时间限制小于准备时间,那么这天就没有有效工作时间。最后问每个人最早能在哪一天完成工作总时长。

        首先,很显然我们是要按照不同人的准备时间来进行排序,因为有了这个排序我们就能够递增的处理准备时间。然后对于单个人的最早完成天数,我们显然可以用二分答案的方式。我们提前计算出前缀和,然后二分一个天数,用前缀和减去天数对应的准备时间即可。但是这里面有个问题,就是无法处理某些天的工作时限会小于准备时间的情况。因为这种情况下,我们的有效工作时间是0,而不是那天的时限减去准备时间。

        对于这个问题,我们何不把天数也按照时限的大小来排序呢?对于每一天,如果当天的总时间限制已经小于当前人的准备时间了,那么这一天对以后所有的人来说产生的有效工作时间都为0,那么就可以把这一天的工作时间在前缀和数组中去掉。相应的,记录前n天中有多少个有效天数的前缀和也要相应的减少,这样也是利用离线处理的方法,要支持单点修改区间查询,配合上树状数组,就可以在O(NlogNlogN)的时间内完成,其中另一个logN是二分产生的。这里比较特殊的就是用到了两个树状数组,另外要注意要用LL。具体见代码:

#include<bits/stdc++.h>
#define LL long long
#define N 200010

using namespace std;

struct person{int t,s,id;} p[N];
struct node{int t,id;} q[N];
int n,m,t[N],ans[N];

struct BinaryIndexedTree
{
	LL c[N];

	inline int lowbit(int x)
	{
		return x&-x;
	}

	inline void update(int x,LL k)
	{
		while (x<=m)
		{
			c[x]+=k;
			x+=lowbit(x);
		}
	}

	inline LL getsum(int x)
	{
		LL ans=0;
		while (x>0)
		{
			ans+=c[x];
			x-=lowbit(x);
		}
		return ans;
	}
} B,T;

bool cmp1(node a,node b)
{
    return a.t<b.t;
}

bool cmp2(person a,person b)
{
    return a.t<b.t;
}

int cal(int p,int x)
{
    int l=0,r=m,mid,res=0;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if (T.getsum(mid)-(LL)B.getsum(mid)*p<x) l=mid+1;
                                    else r=mid-1,res=mid;
    }
    return res;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        B.update(i,1);
        scanf("%d",&t[i]);
        q[i]=node{t[i],i};
        T.update(i,t[i]);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&p[i].t,&p[i].s);
        p[i].id=i;
    }
    sort(q+1,q+1+m,cmp1);
    sort(p+1,p+1+n,cmp2);
    for(int i=1,j=1;i<=n;i++)
    {
        for(;p[i].t>=q[j].t&&j<=m;j++)
        {
            B.update(q[j].id,-1);
            T.update(q[j].id,-t[q[j].id]);
        }
        if (p[i].t>=q[j].t) break;
        ans[p[i].id]=cal(p[i].t,p[i].s);
    }
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值