当时不会写 暴力超时
想到线段树但是不会写
终于在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; }