bzoj4444: [Scoi2015]國旗計劃

Hanks_o發表於2018-04-22

題目傳送門
好題

解法:
因為區間互不包含。
那麼左端點在區間內最右邊的的區間一定是當前區間能擴充套件到最遠的區間。
這句話有點繞。舉個例子。

假設當前區間為1~5。
那麼我們往右擴充套件。
找到左端點最右且小於等於5的區間。
這個區間一定是最優解。
因為區間互不包含啊。如果這個區間不是最優解的話那麼就被別的包含了。。

因為題目是環。需要轉化成鏈。
所以把環複製一份放在後面就變成了鏈了。

如果當前區間起點為l。整個環長度為mx。
那麼我們需要覆蓋l到l+mx

然後我們把這個區間能擴充套件到的最右端看做一個父子關係。
從l到l+mx這個過程我們可以看做找到一個祖先是大於等於l+mx的。
這個過程倍增實現就行。

然後通過貪心可以發現每個區間參與的答案相差都不超過1的。
那麼我們求出第一個區間參與的答案。
以後的答案我們分別用前面的答案-1,0,+1來驗證即可

程式碼實現:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int L[210000],R[210000],l[210000],r[210000],A[410000];
bool cmp(int a,int b) {return a<b;}int n,m,len;
int pos(int x) {
    int l=1,r=len,mid,ans=0;
    while(l<=r) {
        mid=(l+r)/2;
        if(A[mid]>=x) {
            if(A[mid]==x)ans=mid;
            r=mid-1;
        }else l=mid+1;
    }return ans;
}
struct node {int l,r;}s[410000];int mx[21][1100000],bin[21];
bool cmp1(node n1,node n2) {return n1.l<n2.l;}
int jump(int x,int k) {for(int i=20;i>=0;i--)if((k&bin[i]))x=mx[i][x];return x;}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {scanf("%d%d",&L[i],&R[i]);A[++len]=L[i];A[++len]=R[i];}
    sort(A+1,A+1+len,cmp);int mmax=0;
    for(int i=1;i<=n;i++) {l[i]=pos(L[i]);r[i]=pos(R[i]);mmax=max(mmax,max(l[i],r[i]));}
    len=0;
    for(int i=1;i<=n;i++) {
        if(l[i]>r[i])r[i]+=mmax;
        s[++len].l=l[i];s[len].r=r[i];
        s[++len].l=l[i]+mmax;s[len].r=min(r[i]+mmax,2*mmax);
    }sort(s+1,s+1+len,cmp1);
    int t=1,F=0;memset(mx,0,sizeof(mx));
    for(int i=1;i<=2*mmax;i++) {
        while(s[t].l<=i&&t<=2*n) {F=s[t].r;t++;}
        mx[0][i]=F;
    }
    bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]*2;
    for(int j=1;j<=20;j++)for(int i=1;i<=2*mmax;i++)mx[j][i]=mx[j-1][mx[j-1][i]];
    int ans;
    for(ans=0;ans<n;ans++)if(jump(r[1],ans)>=l[1]+mmax) break;
    printf("%d",ans+1);
    for(int i=2;i<=n;i++) {
        if(jump(r[i],ans-1)>=l[i]+mmax)printf(" %d",ans);
        else if(jump(r[i],ans)>=l[i]+mmax)printf(" %d",ans+1);
        else printf(" %d",ans+2);
    }
    return 0;
}

相關文章