1. 程式人生 > >BZOJ1178 [Apio2009]CONVENTION會議中心 貪心 set

BZOJ1178 [Apio2009]CONVENTION會議中心 貪心 set

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