【洛谷6940】[ICPC2017 WF] Visual Python++(掃描線)
阿新 • • 發佈:2021-06-11
- 給定\(n\)個左上角和\(n\)個右下角,要求將它們匹配,使得\(n\)個矩形的邊界無交,或判斷無解。
- \(n\le10^5\)
構造方案
對於當前右下角\((x,y)\),容易想到去找到滿足\(a\le x,b\le y\)的所有尚未匹配的左上角\((a,b)\)中\(b\)最大的那個,讓\((a,b)\)和\((x,y)\)匹配。
然後發現其實這是唯一構造方案,因為假設選擇了另一個滿足\(c\le x,d\le y\)的尚未匹配的左上角\((c,d)\),則\((a,b)\)要麼被困在了矩形內(\(a\ge c\)),要麼就因為這個矩形的阻隔再也不可能匹配了(\(a<c\)
既然如此,只需判斷這個方案是否合法即可。
檢驗合法
先考慮按照橫座標順序列舉,判斷縱方向上是否存在相交區間。(之後還要把橫縱座標交換再檢驗一遍)
這裡要先提一個細節,就是橫座標相同時同類型區間(型別指加入/刪除)不能存在包含關係,要特殊判斷。(當然更不能相交,但相交在之後會一起判掉)
而要判是否存在區間相交,考慮我們把記下所有端點,則當前區間\([l,r]\)中不能包含任何一個已有的端點。
只需找到大於等於\(l\)的第一個點判斷是否在\([l,r]\)中即可,可以直接用一個\(set\)維護下所有端點。
程式碼:\(O(nlogn)\)
#include<bits/stdc++.h> #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> #define Reg register #define RI Reg int #define Con const #define CI Con int& #define I inline #define W while #define N 100000 #define NA() (puts("syntax error"),exit(0))//無解 using namespace std; int n,ans[N+5]; struct P {int p,x,y;I bool operator < (Con P& o) Con {return x^o.x?x<o.x:y<o.y;}}p[2*N+5]; struct OP {int x,l,r,op;I bool operator < (Con OP& o) Con {return x^o.x?x<o.x:(op^o.op?op<o.op:l<o.l);}}w[2*N+5]; set<pair<int,int> > S;I void Get()//構造方案 { set<pair<int,int> >::iterator it;sort(p+1,p+2*n+1);for(RI i=1;i<=2*n;++i) { if(p[i].p<=n) {S.insert(make_pair(p[i].y,p[i].p));continue;}//左上角 ((it=S.lower_bound(make_pair(p[i].y+1,0)))==S.begin())&&(NA(),0),ans[(--it)->second]=p[i].p,S.erase(it);//右下角,找到縱座標儘可能大的,找不到就無解 } } set<int> V;I void Check()//檢驗合法 { RI i;for(i=1;i<=n;++i) w[i]=(OP){p[i].x,p[i].y,p[ans[i]].y,1},w[i+n]=(OP){p[ans[i]].x+1,p[i].y,p[ans[i]].y,0}; RI o,lst[2]={0,0};for(sort(w+1,w+2*n+1),i=1;i<=2*n;++i)//特殊處理橫座標相同的區間 o=lst[w[i].op],lst[w[i].op]=i,w[o].x==w[i].x&&(w[o].l==w[i].l||w[o].r>=w[i].r)&&(NA(),0);//不能存在包含關係 set<int>::iterator it,jt;for(V.insert(0),V.insert(2e9),i=1;i<=2*n;++i)//掃描線 { if(!w[i].op) {it=V.find(w[i].l),w[i].l^w[i].r&&(V.erase(++(jt=it)),0),V.erase(it);continue;}//刪除 *V.lower_bound(w[i].l)<=w[i].r&&(NA(),0),V.insert(w[i].l),V.insert(w[i].r);//加入,不能包含任何端點 } } I bool cmp(Con P& x,Con P& y) {return x.p<y.p;} int main() { RI i;for(scanf("%d",&n),i=1;i<=2*n;++i) scanf("%d%d",&p[i].x,&p[i].y),p[i].p=i; for(Get(),sort(p+1,p+2*n+1,cmp),Check(),i=1;i<=2*n;++i) swap(p[i].x,p[i].y);Check();//先構造方案,然後交換橫縱座標檢驗兩次 for(i=1;i<=n;++i) printf("%d\n",ans[i]-n);return 0; }