题意:n个人,每个人有money和friendship,求最大的friendship和,要求所选的人money之差小于d
思路:先按money排序,然后扫一遍,两个指针l,r记录当前二分范围,Prem记录当前所选人中最小的money。
注意:如果二分找到k,a[i].m-d>=a[k].m,当前t就等于a[i].m。r<l时,r=l。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#define ll __int64
using namespace std;
const int INF=0x3fffffff;
const int N=100100;
struct Node {
ll m,s;
} a[N];
ll n,d;
ll b[N];
ll sum[N];
bool cmp(Node x,Node y)
{
return x.m<y.m;
}
int Lower_bound(int l,int r,int x)
{
int mid;
while(l<=r){
mid=(l+r)/2;
if(x>=a[mid].m){
l=mid+1;
}
else{
r=mid-1;
}
}
return l;
}
int main()
{
//freopen("d:\\Test.txt","r",stdin);
scanf("%I64d%I64d",&n,&d);
for(int i=0; i<n; i++) {
ll w,v;
scanf("%I64d%I64d",&w,&v);
a[i].m=w;
a[i].s=v;
}
sort(a,a+n,cmp);
sum[0]=a[0].s;
for(int i=1;i<n;i++){
sum[i]=sum[i-1]+a[i].s;
}
ll l=0,r=0;
ll Prem=a[0].m;
ll ans=a[0].s;
ll t=a[0].s;
for(int i=1; i<n; i++) {
if(a[i].m-Prem<d){
t+=a[i].s;
ans=max(ans,t);
Prem=min(a[i].m,Prem);
r++;
}
else{
int k=Lower_bound(l,r,a[i].m-d);
if(a[i].m-d>=a[k].m) t=sum[i]-sum[k];
else t=sum[i]-sum[k-1];
l=k;
//cout<<i<<" "<<k<<" "<<t<<endl;
if(r<l) r=l;
Prem=a[k].m;
ans=max(ans,t);
}
}
cout<<ans<<endl;
return 0;
}