BZOJ1178 [Apio2009]CONVENTION會議中心 貪心 set
阿新 • • 發佈:2017-08-18
emp r+ putc put 並且 多少 tor con live
歡迎訪問~原文出處——博客園-zhouzhendong
去博客園看該題解
題目傳送門 - BZOJ1178
題意概括
一堆線段,現在取出最多條數,並輸出字典序最小的方案。
題解
這題好坑。
首先,註意一點,最後不能有多余的空格。
第一問就是基礎的線段覆蓋。
關鍵在於第二問。
我們要準備一個函數—— Get_Ans(L,R),用來求解L~R這個區間內,最多可以取多少線段。
這個可以O(log n)解決。前提是倍增預處理。
然後就是關鍵部分。
我們按照字典序從小到大,能選擇就選擇。
怎麽判斷是否可以選擇?只需要在之前選擇的線段空隙中可以放這個線段,並且滿足Get_Ans(這個線段到它左邊的第一條線段之前)+Get_Ans(它到它右邊的第一個線段之前)+1 = Get_Ans(他左右兩端的),那麽就可以放進去。
代碼
#include <cstring> #include <algorithm> #include <cstdio> #include <cmath> #include <cstdlib> #include <set> using namespace std; const int N=200000+5,Inf=1e9; struct seg{ int L,R; bool operator < (const seg x) const { if (L==x.L) return R>x.R; return L<x.L; } }s[N],s2[N]; int n,rn,Hash[N*2],hs,p[N][20],L[N]; bool alive[N],vis[N*2]; set <int> S; void HASH(){ sort(Hash+1,Hash+hs+1); int hs_=1; for (int i=2;i<=hs;i++) if (Hash[i]!=Hash[i-1]) Hash[++hs_]=Hash[i]; hs=hs_; } void Delete(){ for (int i=1;i<=n;i++) s2[i]=s[i]; sort(s+1,s+n+1); memset(alive,true,sizeof alive); int MinR=Inf,n_=0; for (int i=n;i>=1;i--) if (MinR>s[i].R) MinR=s[i].R; else alive[i]=0; for (int i=1;i<=n;i++) if (alive[i]) s[++n_]=s[i]; n=n_; } void Get_Pos(){ memset(p,0,sizeof p); for (int i=1;i<=n;i++) L[i]=s[i].L; L[n+1]=Inf; for (int i=1;i<=n;i++){ p[i][0]=upper_bound(L+1,L+n+2,s[i].R)-L; if (p[i][0]==n+1) p[i][0]=0; } for (int i=1;i<=18;i++) for (int j=1;j<=n;j++) p[j][i]=p[p[j][i-1]][i-1]; } int Get_Ans(int Le,int Ri){ if (Le>Ri||Le>hs) return 0; int ans=1,pos=lower_bound(L+1,L+n+2,Le)-L; if (pos>n||Ri<s[pos].R) return 0; for (int i=18;i>=0;i--){ if (!p[pos][i]||s[p[pos][i]].R>Ri) continue; pos=p[pos][i]; ans+=1<<i; } return ans; } int main(){ scanf("%d",&n),rn=n; for (int i=1;i<=n;i++){ scanf("%d%d",&s[i].L,&s[i].R); Hash[++hs]=s[i].L; Hash[++hs]=s[i].R; } HASH(); for (int i=1;i<=n;i++){ s[i].L=lower_bound(Hash+1,Hash+hs+1,s[i].L)-Hash; s[i].R=lower_bound(Hash+1,Hash+hs+1,s[i].R)-Hash; } Delete(); Get_Pos(); printf("%d\n",Get_Ans(1,hs)); S.clear(); S.insert(Inf),S.insert(-Inf); bool empty_block=0; for (int i=1;i<=rn;i++){ int now=*S.lower_bound(s2[i].L); if (now==Inf||!vis[now]){ if (now<=s2[i].R) continue; int left=*--S.lower_bound(s2[i].L); int right=*S.lower_bound(s2[i].R); int val=Get_Ans(left+1,s2[i].L-1)+1+Get_Ans(s2[i].R+1,right-1); if (val<Get_Ans(left+1,right-1)) continue; S.insert(s2[i].L); S.insert(s2[i].R); if (s2[i].L!=s2[i].R) vis[s2[i].R]=1; if (empty_block) putchar(‘ ‘); printf("%d",i); empty_block=1; } } return 0; }
BZOJ1178 [Apio2009]CONVENTION會議中心 貪心 set