題目鏈接:https://codeforces.com/contest/1284/problem/D
題目大意:
有n場表演,有兩個場地,如果在a場地表演則需要佔用[sai,eai]這段時間,在b場地表演則需要佔用 [sbi,ebi] 這段時間。如果兩個表演,佔用了同一個時間點,則認爲這兩個表演是衝突的。但因爲每個表演在a場地和b場地的時間段不同,有表演可能在一個場地衝突而在另一個不衝突。所以所有表演中任取兩個表演是否都滿足都衝突或者都不衝突,。
Input
3
1 3 2 4
4 5 6 7
3 4 5 5
OutputNo
題解:
很好很巧妙的一道題,需要用到線段樹|ST表維護最大值+二分。
大致思路:我們可以先枚舉在a場地的表演,按照sa和ea升序排序,然後二分求出和a場地衝突的所有表演場次,然後再用線段樹維護這些衝突的表演的sb的區間最小值和eb的區間最大值。
爲什麼要維護這個呢?因爲基於這樣一個事實,對於兩個表演[s1,e1]和[x,y],如果兩個表演不衝突那麼需要滿足s1>y||e1<x。而對於多個表演[s1,e1],[s2,e2].......都與[x,y]衝突,則不存在si>y||ei<x,因此如果max(s1....si)>y||min(e1...ei)<x,則存在表演與[x,y]不衝突。
這樣我們可以首先線段樹維護sb的所有區間最大值和eb的所有區間最小值,然後二分求出與a場地衝突的表演場次的區間,查詢這個區間內的sb的最大值以及eb的最小值,判斷是否符合條件就行了。
這裏二分有一個很重要的技巧,如果兩個表演衝突的話,那麼需要滿足max(s1,s2)<=min(e1,e2)
對於一個表演[s1,e1],我們二分找到[e1,INF]的位置pos,因爲max(s1,e1)<=min(e1,INF) -> e1<=e1,而對於[i+1,pos]的a表演都和當前位置的表演衝突,因爲pos位置前面的表演要麼sa小要麼ea小。
這裏只考慮了在a場地表演衝突,b場地表演不衝突的情況,沒有考慮b場地表演衝突,a場地表演不衝突的情況,這裏我們只需要把sa和sb,以及ea和eb交換一下。
很巧妙的一道題。
代碼實現:
#pragma GCC optimize(2) #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #define PI atan(1.0)*4 #define E 2.718281828 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define mp make_pair #define pb push_back #define debug printf("ac\n"); using namespace std; inline int read() { int a=0,b=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') b=-1; c=getchar(); } while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+c-'0'; c=getchar(); } return a*b; } const int INF = 0x3f3f3f3f; const int N = 1e5+7; struct node{ int sa,ea,sb,eb; node(){}; node(int sa,int ea,int sb,int eb):sa(sa),ea(ea),sb(sb),eb(eb){}; bool operator<(const node& others){ return sa==others.sa?ea<others.ea:sa<others.sa; } }p[N]; int MAX[N<<2],MIN[N<<2]; void pushup(int rt){ MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); MIN[rt]=min(MIN[rt<<1],MIN[rt<<1|1]); } void build(int l,int r,int rt){ if(l==r){ MAX[rt]=p[l].sb; MIN[rt]=p[l].eb; return ; } int m=l+r>>1; build(lson); build(rson); pushup(rt); } int queryMIN(int l,int r,int rt,int ql,int qr){ if(ql<=l&&r<=qr) return MIN[rt]; int m=l+r>>1; if(qr<=m) return queryMIN(lson,ql,qr); else if(ql>=m) return queryMIN(rson,ql,qr); else return min(queryMIN(lson,ql,m),queryMIN(rson,m+1,qr)); } int queryMAX(int l,int r,int rt,int ql,int qr){ if(ql<=l&&r<=qr) return MAX[rt]; int m=l+r>>1; if(qr<=m) return queryMAX(lson,ql,qr); else if(ql>=m) return queryMAX(rson,ql,qr); else return max(queryMAX(lson,ql,m),queryMAX(rson,m+1,qr)); } bool solve(int n){ sort(p+1,p+1+n); build(1,n,1); rp(i,1,n){ int pos=lower_bound(p+1,p+1+n,node(p[i].ea,INF,0,0))-p-1; if(i+1>pos) continue; if(queryMIN(1,n,1,i+1,pos)<p[i].sb||queryMAX(1,n,1,i+1,pos)>p[i].eb) return false; } return true; } int main(){ int n=read(); rp(i,1,n) p[i].sa=read(),p[i].ea=read(),p[i].sb=read(),p[i].eb=read(); int cnt=0; if(solve(n)) cnt++; rp(i,1,n) swap(p[i].sa,p[i].sb),swap(p[i].ea,p[i].eb); if(solve(n)) cnt++; if(cnt==2) cout<<"Yes"<<endl; else cout<<"No"<<endl; return 0; }
CodeForces1284D New Year and Conference——線段樹|ST表+二分
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.