zoukankan      html  css  js  c++  java
  • BZOJ4444 : [Scoi2015]国旗计划

    首先将坐标离散化,因为区间互不包含,可以理解为对于每个起点输出最少需要多少个战士。

    将环倍长,破环成链,设$f[i]$表示区间左端点不超过$i$时右端点的最大值,可以通过$O(n)$递推求出。

    那么如果将$f[i]$看成$i$的祖先的话,它实际上形成了一棵以$2n$为根的树。

    首先暴力计算出1号点的答案$t$,设$L=t-1$。

    然后dfs这棵树,用一个栈按深度依次保存每个点到根路径上的点。

    对于一个点,只需要从$L$开始暴力枚举答案,然后$O(1)$检验即可。

    因为每个点的答案相差不超过1,所以除去离散化后,整个算法的时间复杂度为$O(n)$。

    #include<cstdio>
    #include<algorithm>
    #define N 400010
    int n,m,i,x,y,L,a[N/2][2],b[N],st[N/2],f[N*2],g[N*2],nxt[N*2],q[N*2],t,ans[N];
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline int lower(int x){
      int l=1,r=m,mid,t;
      while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    inline void up(int&x,int y){if(x<y)x=y;}
    void dfs(int x){
      q[++t]=x;
      if(x<=m)for(int i=L;;i++)if(q[t-i]>=x+m){ans[x]=i;break;}
      for(int i=g[x];i;i=nxt[i])dfs(i);
      t--;
    }
    int main(){
      read(n),read(m);
      for(m=0,i=1;i<=n;i++)read(a[i][0]),read(a[i][1]),b[++m]=a[i][0],b[++m]=a[i][1];
      for(std::sort(b+1,b+m+1),i=1;i<=n;i++){
        st[i]=x=lower(a[i][0]),y=lower(a[i][1]);
        if(x<y)up(f[x],y),up(f[x+m],y+m);
        else up(f[1],y),up(f[x],y+m),up(f[x+m],m+m);
      }
      for(i=1;i<=m+m;i++)up(f[i],f[i-1]);
      for(i=1;i<m+m;i++)nxt[i]=g[f[i]],g[f[i]]=i;
      for(L=-1,i=1;i<=m;i=f[i])L++;
      dfs(m+m);
      for(i=1;i<=n;i++)printf("%d ",ans[st[i]]);
      return 0;
    }
    

      

  • 相关阅读:
    hdu 4334 Trouble
    hdu 4324 Triangle LOVE
    hdu 4255 A Famous Grid
    hdu 3549 Flow Problem
    hdu 3371 Connect the Cities
    hdu 2846 Repository
    hdu 2120 Ice_cream's world I
    P3304 [SDOI2013]直径(【模板】树直径的必经边)
    P5490 【模板】扫描线
    P1364 医院设置(【模板】树的重心)
  • 原文地址:https://www.cnblogs.com/clrs97/p/5304387.html
Copyright © 2011-2022 走看看