悽慘...
寫個題解反思一下。
題目鏈接:
https://codeforces.ml/contest/1284/problem/D
題目大意:
有n個活動要安排,第i個活動在a會場舉行 會佔用[sa,ea]這段時間,在b會場舉行會佔用[sb,eb]這段時間。定義一些活動是敏感的:有兩個活動在一個場地舉行衝突而在另一個場地舉行不衝突。問是否存在兩兩活動是敏感的。
題目思路:
這題開始繞進去了...
果然睡一覺是解決問題的最好辦法.
首先,對於任何一個區間[sa.sb],可以找出與他有相交的區間範圍:所有 sai >= sa && sai <= ea 的都與當前這個區間相交,也就是說左端點在這個區間內,就必相交(這裏不用解釋
相交就代表着衝突,所以我們需要看一下,這些區間內的在b場地是否衝突,我們的任務是找到一個不衝突的此時就可以返回false了,所以說這是一個存在性命題,存在性的話只需要最大值大於最大值,最小值小於最小值即可,所以我們記一下這些區間b場地右端點的最小值與b場地左端點的最大值,當且僅當 最小值<當前區間b場地左端點 或者 最大值 > 當前區間b場地右端點時,存在不衝突的現象(區間沒有相交)
所以此時,就需要再維護一下 這些點的最小值與最大值。
怎麼維護呢?
可以用sa建線段樹,每次看一下滿足條件的 sai >= sa && sai <= ea,區間的最大值與最小值。
上述思路就會很繞,我就繞進去了。
所以這裏我們完全可以考慮一下排序(降維),按照sa升序,這樣一來,每個區間的衝突的範圍就變爲一段連續的區間,此時只需要知道這段區間內的最大值與最小值即可。
這樣就不用過多的處理線段樹的細節
當然這裏沒用線段樹,涉及到靜態區間詢問,所以直接st表即可。
Note:當然這裏只是考慮了在a衝突,在b不衝突的情況 ,還需要反過來進行考慮一下a不衝突,b衝突的情況。
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e17;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
struct node{
ll s1,e1,s2,e2;
bool friend operator<(node a,node b){
if(a.s1==b.s1) return a.e1<b.e1;
return a.s1<b.s1;
}
}save[maxn];
ll st_max[maxn][25];
ll st_min[maxn][25];
ll lg[maxn];
void work()
{
ll cnt=0;
for(int i=1;i<=n;i++)
lg[i]=lg[i/2]+1;
for(int i=1;i<=n;i++){
st_max[i][0]=save[i].s2;
st_min[i][0]=save[i].e2;
}
for(int j=1;j<=22;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
st_max[i][j]=max(st_max[i][j-1],st_max[i+(1<<(j-1))][j-1]);
st_min[i][j]=min(st_min[i][j-1],st_min[i+(1<<(j-1))][j-1]);
}
}
ll query_max(ll x,ll y)
{
ll len=lg[y-x+1]-1;
return max(st_max[x][len],st_max[y-(1<<len)+1][len]);//爲啥+1
}
ll query_min(ll x,ll y)
{
ll len=lg[y-x+1]-1;
return min(st_min[x][len],st_min[y-(1<<len)+1][len]);//爲啥+1
}
auto biarySearch(int x,int y){///找一下區間衝突
int ans_s=-1;
int l = 1,r = n;
while(l<=r){
int mid=(l+r)/2;
if(save[mid].s1>=x){
r=mid-1;
ans_s=mid;
}
else l=mid+1;
}
// printf("%d\n",ans_s);
if(ans_s==-1) return make_pair(-1,-1);
int ans_e=-1;
l = 1 ,r = n;
while(l<=r){
int mid=(l+r)/2;
if(save[mid].s1<=y){
l=mid+1;
ans_e=mid;
}
else r=mid-1;
}
// debug(y);
// debug(save[ans_e].s1);
//printf("%d\n",ans_e);
if(ans_e==-1) return make_pair(-1,-1);
return make_pair(ans_s,ans_e);
}
int Solve(){
sort(save+1,save+1+n);
work();
for(int i=1;i<=n;i++){
auto p = biarySearch(save[i].s1,save[i].e1);
// debug(p.first);
// debug(p.second);
if(p.first != -1){
ll tempmin = query_min(p.first,p.second);
ll tempmax = query_max(p.first,p.second);
if(tempmin<save[i].s2||tempmax>save[i].e2){
return 0;
}
}
}
return 1;
}
int main(){
read(n);
for(int i=1;i<=n;i++){
read(save[i].s1);
read(save[i].e1);
read(save[i].s2);
read(save[i].e2);
}
int f1 = Solve();
for(int i=1;i<=n;i++){
swap(save[i].s1,save[i].s2);
swap(save[i].e1,save[i].e2);
}
int f2 = Solve();
if(f1&&f2) puts("YES");
else puts("NO");
return 0;
}
/**
4
1 3 3 4
2 3 3 4
3 3 3 4
4 4 3 4
**/