【Codeforces 1284D】New Year and Conference

悽慘...

 寫個題解反思一下。

題目鏈接:

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
**/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章