标签:continue 集合 not struct col point 时间 线段 lse
链接: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 }
codeforces 1284D. New Year and Conference(线段树)
标签:continue 集合 not struct col point 时间 线段 lse
原文地址:https://www.cnblogs.com/AaronChang/p/12185459.html