[noi795]保镖

容易证明,最终方案一定是某一个排列无限循环,那么就要满足$sum ai<=max(bi+ai)$,对所有数按照ai+bi排序后,枚举最大值,用权值线段树维护之前的ai最少要选几个

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 500005
 4 #define ll long long
 5 #define mid (l+r>>1)
 6 int V,n,r,ans,f[N*40],ls[N*40],rs[N*40];
 7 ll sum[N*40];
 8 struct ji{
 9     ll a,b;
10     bool operator <(const ji &k)const{
11         return a+b<k.a+k.b;
12     }
13 }a[N];
14 void update(int &k,ll l,ll r,ll x){
15     if (!k)k=++V;
16     if (l==r){
17         f[k]++;
18         sum[k]+=x;
19         return;
20     }
21     if (x<=mid)update(ls[k],l,mid,x);
22     else update(rs[k],mid+1,r,x);
23     f[k]=f[ls[k]]+f[rs[k]];
24     sum[k]=sum[ls[k]]+sum[rs[k]];
25 }
26 int query(int k,ll l,ll r,ll x){
27     if (!k)return 0;
28     if (l==r)return (x+l-1)/l;
29     if (sum[rs[k]]>=x)return query(rs[k],mid+1,r,x);
30     return f[rs[k]]+query(ls[k],l,mid,x-sum[rs[k]]);
31 }
32 int main(){
33     scanf("%d",&n);
34     for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].a,&a[i].b);
35     sort(a+1,a+n+1);
36     ans=n+1;
37     for(int i=1;i<=n;i++){
38         if (sum[1]>=a[i].b)ans=min(ans,query(r,1,1e12,a[i].b)+1);
39         update(r,1,1e12,a[i].a);
40     }
41     if (ans>n)ans=-1;
42     printf("%d",ans);
43 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11750184.html