21.7.7 t3
tag:贪心,扫描线,二分图匹配
结果是最水的一道
首先要想到一个贪心结论:一定是两两匹配,若干个形如 \(x\to y\to x\) 的环。
然后可以二分图匹配。
观察匹配的条件:
- \(a_i\ge j\)
- \(i\le b_j\)
如果用二维点表示为 \((a_i,i)\) 和 \((j,b_j)\),那么可以看作是一个 \((j,b_j)\) 的点可以匹配右下角所有 \((a_i,i)\)。
然后就是另一个贪心,先扫描线从右往左,然后贪心匹配范围内最上面的一个。
复杂度 \(O(nlogn)\)
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void Read(T &n){
char ch; bool flag=false;
while(!isdigit(ch=getchar())) if(ch=='-')flag=true;
for(n=ch^48; isdigit(ch=getchar()); n=(n<<1)+(n<<3)+(ch^48));
if(flag) n=-n;
}
#define no !
typedef long long ll;
enum{
MAXN = 500005
};
struct point{
int x, y, opt;
inline bool operator <(const point &k)const{
if(x!=k.x) return x>k.x;
if(y!=k.y) return y<k.y;
return opt>k.opt;
}
}p[MAXN<<1];
int n, m;
int a[MAXN], b[MAXN], c[MAXN], d[MAXN];
ll ans;
typedef pair<int,int> pii;
set<pii>st;
set<pii>::iterator it;
int main(){
Read(n); Read(m);
for(int i=1; i<=n; i++) Read(a[i]);
for(int i=1; i<=m; i++) Read(b[i]);
for(int i=1; i<=n; i++) Read(c[i]);
for(int i=1; i<=m; i++) Read(d[i]);
for(int i=1; i<=n; i++) p[i].x = a[i], p[i].y = i, p[i].opt = i;
for(int i=1; i<=m; i++) p[i+n].x = i, p[i+n].y = b[i], p[i+n].opt = -i;
n += m; sort(p+1,p+n+1);
for(int i=1; i<=n; i++){
if(p[i].opt>0) st.insert(pii(-p[i].y,p[i].opt));
else{
int &rem = d[-p[i].opt];
while(rem and !st.empty()){
it = st.lower_bound(pii(-p[i].y,0));
if(it==st.end()) break;
if(c[it->second] <= rem) rem -= c[it->second], ans += c[it->second], c[it->second] = 0, st.erase(it);
else c[it->second] -= rem, ans += rem, rem = 0;
}
}
}
cout<<ans<<'\n';
return 0;
}
/*
3 3
3 1 2
1 2 3
1 1 1
1 1 1
*/