当时不会写 暴力超时
想到线段树但是不会写
终于在zb大爷的指导下过了这个题
zb大爷是厉害啊!
题意是有m个人 n天
接下来n个数 表示每一天有一个时间
接下来m行 两个数 d和r
d表示每个人想工作之前必须每天都做准备的时间
r表示需要工作的总时间
问每个人最早在第几天结束工作
如果某一天的t>一个人的d 那么这个人可在这一天工作t-d小时
一个人需要工作的总时间是r
如果按d和t排序
从大往小了来 这样遇到每一天时,插入到线段树里
遇到人时 查询区间和 区间和-d*区间里的天数>=r时表示可以在这一段区间里完成工作
真巧妙啊
*需要注意一点的是区间和可能爆int
数据结构给人的感觉就是 我会写但是我不会用
#include<bits/stdc++.h>
using namespace std;
const int lim = 2e5+10;
int m,n;
long long sum[lim<<2];
int cnt[lim<<2];
struct self
{
int d,r,k;
int pos;
}s[lim<<2];
int cmp(self a,self b)
{
return a.d==b.d?a.k<b.k:a.d<b.d;
}
int ans[lim];
void build(int o,int l,int r)
{
if(l==r)
{
sum[o]=cnt[o]=0;
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
}
void add(int o,int l,int r,int i)
{
if(l==r)
{
sum[o]+=(long long)s[i].d;
cnt[o]++;
return;
}
sum[o]+=(long long)s[i].d;
cnt[o]++;
int mid=(l+r)>>1;
if(s[i].pos<=mid)
add(o<<1,l,mid,i);
else
add(o<<1|1,mid+1,r,i);
}
int query(int o,int l,int r,int i,int has)
{
if(l==r)
return l;
int mid=(l+r)>>1;
if(has+sum[o<<1]-cnt[o<<1]*s[i].d>=s[i].r)
return query(o<<1,l,mid,i,has);
else
return query(o<<1|1,mid+1,r,i,has+sum[o<<1]-cnt[o<<1]*s[i].d);
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,m);
for(int i=1;i<=m;i++)
{
scanf("%d",&s[i].d);
s[i].k=0;
s[i].pos=i;
}
for(int i=m+1;i<=m+n;i++)
{
scanf("%d%d",&s[i].d,&s[i].r);
s[i].k=1;
s[i].pos=i-m;
}
sort(s+1,s+m+n+1,cmp);
for(int i=m+n;i>=1;i--)
{
if(s[i].k==0)
add(1,1,m,i);
else
{
if(sum[1]-cnt[1]*s[i].d>=s[i].r)
ans[s[i].pos]=query(1,1,m,i,0);
}
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}