首先离散化,然后破环成链,那么覆盖住所有边防站相当于再链中覆盖一段[l,l+n],那么强制选择第i为战士就相当于强制左边界为a[i],a[i]表示第i个战士覆盖的左边界。
另外可以发现,任意两个答案之间不会相差超过1。
那么可以令f[i]表示左端点<=i时右端点的最大值,那么覆盖[l,l+n]相当于从i,一路沿着i->f[i]走直到i>=l+n,那么步数就相当于最小覆盖上数。发现这构成了一颗树,因此相当于求树中走到一个点的步数。直接暴力求步数即可,因为相差在1以内。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int n,m,cnt,tp,len,a[N],b[N],ans[N],num[N<<1],f[N<<2],fst[N<<2],nxt[N<<2],stk[N<<2];
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
int find(int x){
int l=1,r=cnt,mid;
while (l<r){
mid=(l+r)>>1;
if (num[mid]<x) l=mid+1; else r=mid;
}
return l;
}
void up(int &x,int y){ if (y>x) x=y; }
void dfs(int x){
stk[++tp]=x; int p;
if (x<=cnt)
for (ans[x]=len; ; ans[x]++)
if (stk[tp-ans[x]]>=x+cnt) break;
for (p=fst[x]; p; p=nxt[p]) dfs(p);
tp--;
}
int main(){
n=read(); int i=read();
for (i=1; i<=n; i++){
num[++m]=a[i]=read(); num[++m]=b[i]=read();
}
sort(num+1,num+m+1);
cnt=1;
for (i=2; i<=m; i++)
if (num[i]!=num[cnt]) num[++cnt]=num[i];
m=cnt<<1;
for (i=1; i<=n; i++){
a[i]=find(a[i]); b[i]=find(b[i]);
if (a[i]<b[i]){
up(f[a[i]],b[i]); up(f[a[i]+cnt],b[i]+cnt);
} else{
up(f[1],b[i]); up(f[a[i]],b[i]+cnt); up(f[a[i]+cnt],m);
}
}
for (i=2; i<=m; i++) up(f[i],f[i-1]);
for (i=1; i<m; i++){
nxt[i]=fst[f[i]]; fst[f[i]]=i;
}
len=-1;
for (i=1; i<=cnt; i=f[i]) len++;
dfs(m);
for (i=1; i<=n; i++) printf("%d ",ans[a[i]]);
return 0;
}
by lych
2016.3.31