赛时累计 2h 想出来的贪心,大样例全部通过。
具体策略是先对商品按 ai−bi 从小到大排序,然后每回找优惠券 j,满足 vj>ai−bi,wj≤ai 且 wj 最大。 同时有一个以 v 为关键字的小根堆,维护已经用过的优惠券,每回对于 v≤ai−bi 的看能不能反悔。
#include <bits/stdc++.h>
#define fr first
#define se second
#define Un unsigned
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define pLi pair<LL,int>
#define pLL pair<LL,LL>
#define __ __int128
#define LD long double
#define VE vector<LL>
#define DB double
#define Ve vector<int>
using namespace std;
inline LL read()
{
LL x = 0,f = 1;char ch = getchar();
while(!isdigit(ch)) (ch == '-') && (f = -1),ch = getchar();
while(isdigit(ch)) x = x*10+ch-48,ch = getchar();
return x*f;
}
const int N = 1e6+5,INF = 2e9;
int a[N],b[N],w[N],v[N],c[N];
multiset < pii > s;
priority_queue < pii,vector<pii>,greater<pii> > q1,q2;
int main()
{
int n = read(),m = read();LL sum = 0;
for (int i = 1;i <= n;i++) a[i] = read(),b[i] = read(),c[i] = i;
for (int i = 1;i <= m;i++) w[i] = read(),v[i] = read(),s.insert({w[i],v[i]}),q1.push({v[i],w[i]});
sort(c+1,c+n+1,[](int x,int y){return a[x]-b[x] < a[y]-b[y];});
for (int i = 1;i <= n;i++)
{
while (q1.size() && q1.top().fr <= a[c[i]]-b[c[i]])
{
auto it = s.find({q1.top().se,q1.top().fr});
if(it != s.end()) s.erase(it);
q1.pop();
}
while (q2.size() && q2.top().fr <= a[c[i]]-b[c[i]])
{
auto it = s.upper_bound({q2.top().se,INF});
if (it != s.begin())
{
it--,sum = sum+q2.top().fr-(*it).se;
q2.push({(*it).se,(*it).fr}),s.erase(it);
}
q2.pop();
}
auto it = s.upper_bound({a[c[i]],INF});
if (it != s.begin())
{
it--,sum += a[c[i]]-(*it).se;
q2.push({(*it).se,(*it).fr}),s.erase(it);
}
else sum += b[c[i]];
}
cout << sum;
return 0;
}