#4617. 逛公园
题目描述
小凯做题做累了,他想去逛公园。
公园里有 $m$ 个亲子项目,每个项目一天只能一个家庭参加。一共有 $n$ 个家庭,第 $i$ 个家庭希望在第 $l_i$ 到 $r_i$ 天内参加恰好一次第 $p_i$ 个项目。但是公园的工作人员很懒,他们希望上班的天数尽量少。某天要上班当且仅当至少有一个家庭参加了任意一个项目。
工作人员看到了小凯,想让他帮忙使得工作人员有更多咕咕咕的机会。但小凯又双叒叕不会了,所以他请你求出这个最少的上班时间。如果无论如何安排都不能达到要求,输出 GG。
数据范围
$n \le 10^5, l,r,m \le 10^9$
题解
挺妙又难写的一道贪心题。
考虑每种类型能否满足,考虑到如果右端点都不同的话,那每个区间都取右端点就好了,于是考虑右端点相同的情况,那我们先让左端点最大的区间先确定这个右端点,剩下区间右端点左移即可,这样我们就可以把一个类型的区间的右端点变得互不相同。
考虑多个类型,首先我们先找到一个还没确定的区间中右端点最小的那个,那对于剩下的类型,如果存在左端点大于等于这个右端点的,那可以把这个区间确定在这个右端点上,如果有多个区间同时满足,根据贪心应该让右端点最小的被确定。
具体实现有点复杂(STL大法好)。
代码
#include <bits/stdc++.h> using namespace std; const int N=1e5+5; int n,m,t,ans,fl[N]; struct O{ int l,r,x; friend bool operator < (const O& A,const O& B){ return A.l<B.l; } }p[N]; struct S{ int l,r,x,i; friend bool operator < (const S& A,const S& B){ return A.r<B.r; } }; multiset<S>s; priority_queue<O>q; priority_queue<S>d[N];vector<O>e[N]; queue<int>h,H; bool cmp(O A,O B){ return A.x!=B.x?A.x<B.x:A.r>B.r; } int main(){ cin>>n>>m; for (int i=1,l,r,x;i<=n;i++) scanf("%d%d%d",&l,&r,&x), p[i]=(O){l,r,x}; sort(p+1,p+n+1,cmp); for (int i=1,j=0,r;i<=n;i=j+1){ while(j<n && p[j+1].x==p[i].x) j++; t++;r=0;for (int k=i;k<=j;k++) p[k].x=t,r=max(p[k].r,r); for (int k=r,c=i;;k--){ if (q.empty()) k=p[c].r; while(c<=j && p[c].r==k) q.push(p[c]),c++; if (!q.empty()){ O u=q.top();u.r=k;q.pop(); if (u.r<u.l) return puts("GG"),0; e[u.x].push_back(u); } if (c>j && q.empty()) break; } } for (int i=1,z,j=0;i<=t;i++){ z=e[i].size(); sort(e[i].begin(),e[i].end()); for (int k=0;k<z;k++) p[++j]=e[i][k]; } sort(p+1,p+n+1); for (int i=1;i<=n;i++) s.insert((S){p[i].l,p[i].r,p[i].x,i}); for (int j=0,i;!s.empty();){ S u=(*s.begin());ans++;s.erase(s.begin());fl[u.i]=1; while(j<n && p[j+1].l<=u.r){ j++;if (fl[j]) continue; if (d[i=p[j].x].empty()) h.push(i); d[i].push((S){p[j].l,-p[j].r,p[j].x,j}); } while(!h.empty()){ int x=h.front();h.pop(); while(!d[x].empty()) if (fl[d[x].top().i]) d[x].pop(); else break; if (d[x].empty()) continue; if (x==u.x){H.push(x);continue;} S v=d[x].top();v.r=-v.r;d[x].pop(); s.erase(s.find(v));fl[v.i]=1;H.push(x); } h=H;while(!H.empty()) H.pop(); } cout<<ans<<endl;return 0; }