BZOJ5397: circular【倍增】

29 篇文章 0 订阅

5397: circular

去掉覆盖的点,求出最优的下一个线段(a[j].L>=a[i].R,min(a[j].R)),直接二分,check用倍增。

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=100005;
int m,n,nn,Stk_Top,Stk[MAXN<<1],Ans,Top,Fa[MAXN<<1][20];bool vis[MAXN<<1];
struct xcw{
    int L,R;
    bool operator <(const xcw b)const{return L<b.L||(L==b.L&&R>b.R);}
}a[MAXN<<1],b[MAXN<<1];
#include<cctype>
int read(){
    int ret=0;char ch=getchar();bool f=1;
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
    return f?ret:-ret;
}
bool check(int x,int p){
    int L=b[p].L;
    for(int j=0;(1<<j)<=x;j++) if((1<<j)&x) p=Fa[p][j];
    if(!p) return 0;
    return L+m>=b[p].R;
}
int main(){
//  freopen("5397.in","r",stdin);
//  freopen("5397.out","w",stdout);
    m=read(),n=read();
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        if(x>y) y+=m;
        a[++Top]=(xcw){x,y},a[++Top]=(xcw){x+m,y+m};
    }
    sort(a+1,a+1+Top);
    for(int i=1;i<=Top;i++){
        while(Stk_Top&&a[Stk[Stk_Top]].R>=a[i].R) vis[Stk[Stk_Top--]]=1;
        Stk[++Stk_Top]=i;
    }
    for(int i=1;i<=Top;i++) if(!vis[i]) b[++nn]=a[i];
    Top=nn;
    for(int i=1,j=1;i<=Top;i++){
        while(b[j].L<b[i].R&&j<=Top) j++;
        if(j>Top) break;Fa[i][0]=j;
    }
    for(int j=1;(1<<j)<=Top;j++)
    for(int i=1;i<=Top;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
    for(int i=1;i<=Top;i++){
        int L=0,R=n-1;
        while(L<=R){
            int mid=(R+L)>>1;
            if(check(mid,i)) L=mid+1;else R=mid-1;
        }
        Ans=max(Ans,R);
    }
    printf("%d\n",Ans+1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值