CF555B Case of Fugitive
题目大意
有一些不相交线段和一些桥,桥可以架在两个相邻的线段上。求现有的桥是否可以使所有线段连通。
题解
在两个线段上架桥,桥的长度在一个范围内,相当于一个长度的区间,一个桥只有一个长度,相当于一个长度的点。这就转化成了点匹配区间问题。
点匹配区间问题我们在贪心(POJ3614)那里学了,把所有区间按照左端点从大到小排序,把点按照位置从大到小排序,每次总是把最右侧区间与在该区间内的最右端点匹配。问题是:如何满足可以随时删除点,且可以快速找到该区间内的最右端点呢?用key值为点的长度递减的multiset的delete和lower_bound函数可以轻松解决。注意delete时传的参数时迭代器(指针),而不是值,否则一删就把重合的点全删了。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <set> using namespace std; const int MAX_LAND = 200010, MAX_BRIDGE = 200010; int TotLand, TotLenRange, TotBridge; int Ans[MAX_BRIDGE]; struct Bridge { long long Len; int OrgP; bool operator < (const Bridge& a) const { return Len > a.Len; } }_bridges[MAX_BRIDGE]; struct Cmp { bool operator () (const Bridge& a, const Bridge& b) { return a.Len < b.Len; } }; struct Land { long long L, R; bool operator < (const Land& a) const { return L < a.L; } }_lands[MAX_LAND]; struct LenRange { long long L, R; int OrgL; bool operator < (const LenRange& a) const { return L > a.L; } }_lenRanges[MAX_LAND]; void Read() { scanf("%d%d", &TotLand, &TotBridge); TotLenRange = TotLand - 1; for (int i = 1; i <= TotLand; i++) scanf("%lld%lld", &_lands[i].L, &_lands[i].R); for (int i = 1; i <= TotBridge; i++) scanf("%lld", &_bridges[i].Len); } void Init() { for (int i = 1; i <= TotBridge; i++) _bridges[i].OrgP = i; sort(_lands + 1, _lands + TotLand + 1); for (int i = 1; i <= TotLand - 1; i++) { _lenRanges[i].L = _lands[i + 1].L - _lands[i].R; _lenRanges[i].R = _lands[i + 1].R - _lands[i].L; _lenRanges[i].OrgL = i; } sort(_lenRanges + 1, _lenRanges + TotLenRange + 1); } void Solve() { static multiset<Bridge> tree; for (int i = 1; i <= TotBridge; i++) tree.insert(_bridges[i]); for (int i = 1; i <= TotLenRange; i++) { Bridge temp; temp.Len = _lenRanges[i].R; multiset<Bridge>::iterator it = tree.lower_bound(temp); if (it == tree.end() || it->Len <_lenRanges[i].L ) { printf("No\n"); return; } Ans[_lenRanges[i].OrgL] = it->OrgP; tree.erase(it); } printf("Yes\n"); for (int i = 1; i <= TotLand - 1; i++) printf("%d ", Ans[i]); printf("\n"); } int main() { Read(); Init(); Solve(); return 0; }