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;
}