21.7.7 t3
阿新 • • 發佈:2021-07-07
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 */