题意:
太难懂了。有一个平面点集,对集合中任意一点(x,y),满足以原点和(x,y)构成的矩形边上和内部的所有点也都在集合里。
现在要给点标号,为了美观,当给(x,y)标号为i时,要求以(x,y)为左下角的矩形边上和内部所有点(如果在集合内)的标号都不小于i。
然后还有一个条件,标号为i的点(x,y)必须满足 y-x == wi。
输入:
一个数n,然后是n个点,最后是n个数wi。
输出:
是否存在满足条件的标号方法,输入YES or NO,YES的话还要按从小到大标的号输出点的坐标。
题解:
先以y-x为关键字把点存进堆里,维护一个最小堆,每次要wi的时候就从wi堆里把根节点拿出来。当wi堆为空的时候显然就无解,否则因为美观的条件,显然每次贪心标x最小的(y也是最小的)是最优的。
然后还要维护以y为下标的一个数组out,表示坐标为y的点已经往右标到的x坐标,维护x坐标严格按1递增,同时y较大的out值不能超过y较小的out值,否则会违反美观原则。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
typedef priority_queue<pii, vector<pii>, greater<pii> > pair_heap;
map<int, pair_heap> heap;
map<int, int> out; // 因为y-x有负数,所以开map做成伪数组
vector<pii>ans;
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
int a, b;
scanf("%d%d", &a, &b);
heap[b-a].push(make_pair(a,b));
}
int flag = 1;
for(int i = 1; i <= n && flag; ++i){
int tmp;
scanf("%d", &tmp);
pair_heap &now = heap[tmp];
if(now.empty()){ flag = 0; break; } // 堆为空就无解
ans.push_back(now.top());
int ansy = now.top().second, ansx = now.top().first;
now.pop();
int &z = out[ansy];
if(z == ansx) {
z += 1; // 维护x依次递增
if(ansy > 0 && z > out[ansy-1]) flag = 0; // 较大的y不能有大的out值
}
else flag = 0;
}
if(!flag){ puts("NO"); return 0; }
puts("YES");
for(auto&i : ans) printf("%d %d\n", i.first, i.second);
}