洛谷P4155 [SCOI2015]國旗計劃(貪心,樹形結構,基數排序)

洛谷題目傳送門html

\(O(n)\)算法來啦!c++

複雜度優化的思路是創建在倍增思路的基礎上的,看看樓上幾位巨佬的描述吧。算法

首先數組倍長是同樣的。倍增法對於快速找到\(j\)知足\(l_j+m\le r_i\)進行了優化。而後菊開隊長說能夠建個樹優化,但是他沒講清楚就把這個神仙東西扔給了我這個蒟蒻。。。一個晚上終於把這個模性建出來了。數組

在倍長的序列上,咱們對於每個\(i\)找到最小的\(j\)知足\(r_j\ge l_i\)並連一條\(i\)\(j\)的邊,因而就成了一個森林。貪心地想,咱們要求的東西就變成了:對於每一個點,找到與它最近的祖先\(j\)知足\(l_j+m\le r_i\)\(j\)\(i\)間的總點數就是答案。下面稱\(j\)\(i\)的決策點。優化

仍是要樹上倍增麼?不不不,咱們來注意一個性質:設不強制選某個戰士的最優答案是\(ans\),那麼若是強制選某一個,答案要麼是\(ans\)要麼是\(ans+1\)。顯然若是一個戰士可以被一個最優方案包含的話就是\(ans\),若是不能,任選一個最優方案再選他本身就能夠了。spa

因而,假設\(x\)的決策點爲\(y\),那麼\(x\)的一個兒子\(x_1\)的決策點,要麼仍是\(y\),要麼是\(y\)\(x\)方向上的兒子。直接從上往下dfs並維護每一個點的決策點就好啦!實現中,找到「\(y\)\(x\)方向上的兒子」能夠用相似Dinic當前弧的方法維護。code

時間複雜度\(O(n)\),常數較大,歡迎超越。爲了理論上的嚴格線性,蒟蒻研究了下鬆爺基排,還寫了個template,好不麻煩。template的食用方法能夠去蒟蒻的blog上看。htm

注意開unsigned int,沒開的話蒟蒻不知道能不能過。blog

#include<bits/stdc++.h>
#define UI unsigned int
#define RG register
#define R RG UI
#define G if(++ip==ie)fread(ip=buf,1,N,stdin)
using namespace std;
const UI N=4e5+9;
struct Data{UI l,r,id;}a[N],b[N];
UI m,he[N],ne[N],at[N],d[N];
char buf[N],*ie=buf+N,*ip=ie-1;
inline UI in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
template<typename T>//基數排序
inline void Radixsort(RG T*fst,RG T*lst,RG T*buf,RG int*op){
    static int b[0x100];
    RG UI Len=lst-fst,Sz=sizeof(T),i,j;
    RG unsigned char*bgn,*end,*it;
    for(i=0;i<Sz;++i){
        if(op[i]==-1)continue;
        bgn=(unsigned char*)fst+i;end=(unsigned char*)lst+i;
        memset(b,0,sizeof(b));
        for(it=bgn;it!=end;it+=Sz)++b[*it];
        for(j=1;j<=0xff;++j)b[j]+=b[j-1];
        for(it=end;it!=bgn;)buf[--b[*(it-=Sz)]]=*--lst;
        lst=buf+Len;swap(fst,buf);
    }
}
void dfs(R x,R y){
    if(a[he[y]].l+m<=a[x].r)
        y=he[y],--d[x];//決策點偏移
    for(R&i=he[x];i;i=ne[i])
        d[i]=d[x]+1,dfs(i,y);
}
int main(){
    R n=in(),i,p;m=in();
    for(i=1;i<=n;++i){
        a[i].l=in();a[i].r=in();a[i].id=i;
        if(a[i].l>a[i].r)a[i].r+=m;//環狀數據處理成鏈意義下的
    }
    Radixsort(a+1,a+n+1,b+1,new int[12]{0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1});
    memcpy(a+n+1,a+1,12*n);
    for(i=n+1;i<=2*n;++i)//倍長處理
        at[a[i-n].id]=i,a[i].l+=m,a[i].r+=m;
    for(p=1,i=2;i<=2*n;++i){//建樹,貪心思想
        while(a[p].r<a[i].l)++p;
        ne[i]=he[p];he[p]=i;
    }
    for(i=1;i<=n;++i)
        if(!d[i])d[i]=1,dfs(i,i);
    for(i=1;i<=n;++i)
        printf("%d ",d[at[i]]);
    puts("");
    return 0;
}
相關文章
相關標籤/搜索