codeforces 589 G. Hiring(线段树,好题)

G. 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个询问,对于每个询问,是关于(准备时间A,完成时间B)的序列
即,我们每天想要工作,要先支出一定的准备时间A。 
然后,这天的总时间,减去准备时间,剩下的时间作为我们的有效工作时间。 
如果有效工作时间(肯定有效工作时间要>0)之和>=完成时间B,那我们就完工啦。 
问最早的完工时间(如果无法完工,输出0) 


参考题解

线段树每个节点存有效天数时间的和值,最小值和区间有效天数,并且离线处理,将询问排序后从小到达查询,每次查询相当于减去准备时间,并采用标记tag,若一个区间的最小值为小于等于0时就维护这个区间,将小于0的那些天去掉(将值设为INF就不会影响区间最小值了)并更新有效天数。细节详见代码。


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
const int MAXN=2e5+100;
const ll INF=0x3fffffffffff;
struct node
{
	int l,r,num;  //num记录有效天数的数量 
	ll sum,tag,mi;  //tag为标记 
}a[MAXN*4];
struct Ans
{
	int id,res;
	ll d,r;
	bool operator <(const Ans& a)const{
	return d<a.d;
	}
}ans[MAXN];
void pushup(int i)
{
	if(a[i].l!=a[i].r)
	{
		a[i].mi=min(a[i*2].mi,a[i*2+1].mi);
		a[i].sum=a[i*2].sum+a[i*2+1].sum;
		a[i].num=a[i*2].num+a[i*2+1].num;
	}
}
void build(int i,int l,int r)
{
	a[i].l=l,a[i].r=r,a[i].tag=0;
	if(l==r)
	{
		scanf("%I64d",&a[i].sum);
		a[i].mi=a[i].sum;
		a[i].num=1;
		return;
	}
	int m=(l+r)/2;
	build(i*2,l,m);
	build(i*2+1,m+1,r);
	pushup(i);
	return;
}
void pushdown(int i)
{
	if(a[i].l!=a[i].r)
	{
		if(a[i].tag)
		{
			a[i*2].sum-=(ll)a[i*2].num*a[i].tag;
			a[i*2+1].sum-=(ll)a[i*2+1].num*a[i].tag;
			a[i*2].tag+=a[i].tag;
			a[i*2+1].tag+=a[i].tag;
			a[i*2].mi-=a[i].tag;
			a[i*2+1].mi-=a[i].tag;
			a[i].tag=0;
		}
	}
}
void del(int i)        //维护结点i 
{
	if(a[i].l==a[i].r)
	{
		a[i].sum=0;
		a[i].mi=INF;
		a[i].num=0;
		return;
	}
	if(a[i].tag) 
	pushdown(i);
	if(a[i*2].mi<=0) del(2*i);
	if(a[i*2+1].mi<=0) del(i*2+1);
	pushup(i);
}
void update(int i,int l,int r,int v)
{
	if(a[i].l==l&&a[i].r==r)
	{
		a[i].sum-=(ll)a[i].num*v;
		a[i].mi-=(ll)v;
		a[i].tag+=(ll)v;
		if(a[i].mi<=0) del(i);
		return;
	}
	if(a[i].tag) pushdown(i);///
	int m=(a[i].l+a[i].r)/2;
	if(r<=m) update(i*2,l,r,v);
	else if(l>m) update(i*2+1,l,r,v);
	else
	{
		update(i*2,l,m,v);
		update(i*2+1,m+1,r,v);
	}
	pushup(i);
}
int query(int i,ll v)
{
	if(a[i].l==a[i].r) return a[i].l;
	if(a[i].tag) 
	pushdown(i);
	if(a[i*2].sum>=v) return query(i*2,v);
	else return query(i*2+1,v-a[i*2].sum);
}
bool cmp(Ans a,Ans b){
	return a.id<b.id;
}
int main()
{
	int n,m;
	scanf("%d%d",&m,&n);
	build(1,1,n);
	rep(i,1,m+1)
	scanf("%I64d%I64d",&ans[i].d,&ans[i].r),ans[i].id=i;
	sort(ans+1,ans+m+1);
	rep(i,1,m+1)
	{
		ll v=ans[i].d-ans[i-1].d;
		if(v) update(1,1,n,v);
		if(ans[i].r>a[1].sum) ans[i].res=0;
		else ans[i].res=query(1,ans[i].r);
	}
	sort(ans+1,ans+m+1,cmp);
	rep(i,1,m+1) printf("%d ",ans[i].res);
	puts("");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值