Work
题目描述
假设现在离 noip 还有 m 天,有 n 个人要去参加比赛。他们每个人都有一个预定的训练量 r[i] ,所以每一天他们都抓紧时间练习。但是由于条件限制,第 i 天只有 t[i] 的时间可以练习。
我们都知道,一个人在开始干活以前总要浪费一些时间做一些杂七杂八的事情。现在我们假定第 i 个人每天在训练前浪费的时间是固定的,记为 d[i] 。这段浪费掉的时间过后,选手会专心致志训练,他们会充分利用剩下的时间。然而一个可能的情况时,一个人还在无所事事的时候,某一天的训练时间已经过去了,所以他那一天什么事情都没有做。
现在请问每个人在第几天的时候可以完成自己的训练任务。当然会存在志向远大但是很懒惰的人到最后也是做不完的情况。
输入格式
第一行两个整数 n,m ,表示人数和天数 。
接下来一行 m 个整数 t[i] 。
接下来 n 行每行两个整数 d[i],r[i] 。
输出格式
一行输出 n 个整数表示每个人在第几天可以完成自己的工作,如果完不成,输出 0 。
样例数据 1
输入 [复制]
3 3
4 2 5
1 3
2 5
3 4
输出
1 3 0
备注
【数据范围】
对 30% 的输入数据 :1≤n,m≤1000
对 100% 的输入数据 :1≤n,m≤ 200000;1≤t[i]≤1000000; 0≤d[i]≤1000000;1≤r[i]≤1000000
【注意事项】
如果某人浪费的时间超过一天,不需减去负的时间。
解析:
对于30%的数据直接O(N ^ 2)暴力就行了。
对于100%的数据,如果二分每个人的所需天数,则时间复杂度为O(N (log M) ^2)(吧)。虽然能过,但是我们要追求更优越的复杂度,于是就可以用线段树了。把 t ,d 数组按从大到小排序,然后从大到小计算第 i 个人的所需天数,方法就是把比 d[i] 大的 t[j] 加入线段树中,再查询就行了。时间复杂度 O(N ^ log N)
代码:
#include <bits/stdc++.h>
using namespace std;
const int Max=200010;
int n,m,s;
int ans[Max];
struct in{int d,r,pos;};
in num[Max];
struct ou{int pos,t;};
ou t[Max];
struct shu{int sum,num;};
shu tree[Max<<2];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') {f=-1;c=getchar();}
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline bool comp1(const ou &a,const ou &b)
{
return a.t > b.t;
}
inline bool comp2(const in &a,const in &b)
{
return a.d > b.d;
}
inline void Insert(int root,int l,int r,int pos,int k)
{
if(l==r)
{
tree[root].sum = k,tree[root].num = 1;
return;
}
int mid = l + r >> 1;
if(pos <= mid) Insert(root<<1 , l , mid , pos , k);
else Insert(root<<1|1 , mid+1 , r , pos , k);
tree[root].sum = tree[root<<1].sum + tree[root<<1|1].sum;
tree[root].num = tree[root<<1].num + tree[root<<1|1].num;
}
inline int Q(int root,int l,int r,int k)
{
if(l==r) return l;
int mid = l + r >> 1;
if(s <= tree[root<<1].sum - tree[root<<1].num * k) Q(root<<1,l,mid,k);
else s-=tree[root<<1].sum - tree[root<<1].num * k,Q(root<<1|1,mid+1,r,k);
}
int main()
{
n=get_int();
m=get_int();
for(int i=1;i<=m;i++) t[i].pos=i,t[i].t=get_int();
for(int i=1;i<=n;i++) num[i].pos=i,num[i].d=get_int(),num[i].r=get_int();
sort(t+1,t+m+1,comp1);
sort(num+1,num+n+1,comp2);
register int l=1;
for(register int i=1;i<=n;i++)
{
for(;l <= m && num[i].d <= t[l].t;l++) Insert(1,1,m,t[l].pos,t[l].t);
if(tree[1].sum - tree[1].num * num[i].d < num[i].r) continue;
s=num[i].r;
int pos = Q(1,1,m,num[i].d);
ans[num[i].pos] = pos;
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
return 0;
}