题意:
一天可以工作ti时间,有n天,问一个工作者最多可以在第几天完成他的工作
一天工作之前必须先要准备xi的时间
由题意可知,要想完成这份工作,一定要在ti>xi的天数中做工作
已经知道了哪几天这个人会去工作,那么显然二分答案
所以问题便成为了求哪几天他会去工作,所以联想到用树状数组去维护,
首先先对时间升序排序,对准备时间升序排序
反向循环,当时间大于准备时间时,便把这天的准备时间加入到树状数组中,同时再利用一个树状数组,对天数+1
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
int n,m;
const int maxn=200000+1000;
int ans[maxn];
__int64 sum[maxn],cnt[maxn];
struct Day{
int id;
__int64 num;
friend bool operator <(Day a,Day b){
return a.num < b.num; //num小的结构体优先
}
}t[maxn];
struct task{
__int64 prepare,cost;
int id;
friend bool operator <(task a,task b){
return a.prepare < b.prepare; //prepare小的结构体优先
}
}people[maxn];
__int64 query(__int64 c[],int x){
__int64 ret=0;
while(x>0){
ret+=c[x];
x-=(x&-x);
}
return ret;
}
void add(__int64 c[],int x,__int64 d){
while(x<=m){
c[x]+=d;
x+=(x&-x);
}
}
bool check(int i,int x){
__int64 tmp1=query(cnt,x),tmp2=query(sum,x);
if(tmp1*people[i].prepare+people[i].cost<=tmp2)
return true;
return false;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=m;i++){
scanf("%I64d",&t[i].num);
t[i].id=i;
}
for(int i=1;i<=n;i++){
scanf("%I64d%I64d",&people[i].prepare,&people[i].cost);
people[i].id=i;
}
sort(t+1,t+m+1);
sort(people+1,people+n+1);
int j=m;
for(int i=n;i>=1;i--){
while(j&&t[j].num>=people[i].prepare){
add(sum,t[j].id,t[j].num);//把能处理任务的天数加进去
add(cnt,t[j].id,1);//把i天处理的天数记录
j--;
}
int low=1,high=m+1;
while(high-low>=0){
int mid=(high+low)/2;
if(check(i,mid))
high=mid-1;
else
low=mid+1;
}
if(high!=m+1)
ans[people[i].id]=low;
else
ans[people[i].id]=0;
}
printf("%d",ans[1]);
for(int i=2;i<=n;i++)
printf(" %d",ans[i]);
printf("\n");
}
return 0;
}