codeforces 1284D. New Year and Conference(线段树)

链接:https://codeforces.com/problemset/problem/1284/D

题意:有n场讲座,有两个场地a和b,如果在a场地开讲座则需要占用[sai,eai],在b场地开讲座则需要占用[sbi,ebi]这个时间段,假如开两场讲座,如果在a场地开不冲突,而b场地开冲突,则称其为敏感的,同理a和b反过来也是一样的,如果ab两场地都冲突则也不是敏感的,先求给定的n场讲座,任意的两两开设是否敏感。

思路:暴力枚举是O(n^2)复杂度,必定超时,这里可以用线段树或ST表做,达到一个nlogn的复杂度。对于任意一个讲座x,找出所有与x讲座在a场地冲突的讲座,再判断其是否在b场地冲突,如果不是则直接输出“NO”

首先对所有讲座的sa和ea进行升序,例如讲座 i 的时间片是[x,y],在其时间片上与 i 在a场地冲突的讲座用二分的方法可以枚举出来一个离散化后的区间,然后我们用线段树维护b场地的sb最大值和eb最小值,每次查询出这个区间的

的sb最大值和eb最小值,此时如果说sb最大值 > y 或者 eb最小值 < x,那么这些表演中必定存在b场地与表演i不冲突的情况,此时直接输出“NO”,把所有的讲座都check一遍,交换ab次序再check即可,上述只检验了在a场地冲突一定在b场地冲突的情况,但并未考虑在b场地冲突而在a场地不冲突的情况。

总体时间复杂度nlogn。

AC代码:

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<cstring>
 8 #include<queue>
 9 #include<map>
10 using namespace std;
11 typedef long long ll;
12 const int maxn = 1e5+200;
13 struct node{
14     int sa,ea,sb,eb;
15     node(){};
16     node(int a,int b,int c,int d){
17         sa = a,ea = b,sb = c,eb = d;
18     }
19     bool operator<(node cur)const{
20         if(sa == cur.sa ) return ea<cur.ea ;
21         return sa < cur.sa ;
22     }
23 }point[maxn];
24 int segt_max[4*maxn],segt_min[4*maxn];
25 void build(int l,int r,int k){//建两个线段树维护区间最大最小值 
26     if(l == r) {
27         segt_max[k] = point[l].sb;
28         segt_min[k] = point[l].eb;
29         return ; 
30     }
31     int mid = (l+r)/2;
32     build(l,mid,2*k);
33     build(mid+1,r,2*k+1);
34     segt_max[k] = max(segt_max[2*k],segt_max[2*k+1]);
35     segt_min[k] = min(segt_min[2*k],segt_min[2*k+1]);
36 }
37 int queryMin(int l,int r,int al,int ar,int k){//查询区间最小值 
38     if(l >= al && r <= ar) return segt_min[k];
39     int mid = (l+r)/2;
40     if(ar<=mid) return queryMin(l,mid,al,ar,2*k);
41     else if(al>mid){
42         return queryMin(mid+1,r,al,ar,2*k+1);
43     }
44     else {
45         return min(queryMin(l,mid,al,mid,2*k),queryMin(mid+1,r,mid+1,ar,2*k+1));
46     }
47 } 
48 int queryMax(int l,int r,int al,int ar,int k){//查询区间最大值 
49     if(l >= al && r <= ar) return segt_max[k];
50     int mid = (l+r)/2;
51     if(ar<=mid) return queryMax(l,mid,al,ar,2*k);
52     else if(al>mid){
53         return queryMax(mid+1,r,al,ar,2*k+1);
54     }
55     else {
56         return max(queryMax(l,mid,al,mid,2*k),queryMax(mid+1,r,mid+1,ar,2*k+1));
57     }
58 } 
59 bool check(int n){
60     sort(point+1,point+1+n);
61     build(1,n,1);
62     for(int i = 1;i<=n;i++){
63         int pos = lower_bound(point+1,point+1+n,node(point[i].ea ,1e9+5000,0,0))-point-1;
64         //查找与第i场演讲冲突的集合 
65         if(i+1>pos) continue;//无冲突直接跳过 
66         //check一下另一个场地的所有表演是否都冲突 
67         if(queryMin(1,n,i+1,pos,1)<point[i].sb || queryMax(1,n,i+1,pos,1)>point[i].eb){
68             return false;
69         }
70     }
71     return true;
72 }
73 int main()
74 {
75     int n;
76     cin>>n;
77     int f = 0;
78     for(int i = 1;i<=n;i++){
79         cin>>point[i].sa>>point[i].ea>>point[i].sb>>point[i].eb;    
80     }
81     if(check(n)) f++;
82     for(int i = 1;i<=n;i++){
83         swap(point[i].sa,point[i].sb);
84         swap(point[i].ea,point[i].eb);
85     }
86     if(check(n)) f++;
87     if(f == 2) cout<<"YES";
88     else cout<<"NO"; 
89     return 0;
90 }

猜你喜欢

转载自www.cnblogs.com/AaronChang/p/12185459.html