链接:点击打开链接
题解:二分预处理出来每个点单次传染到的左右范围,再用线段树维护每个点最终的范围最小值、最大值,利用线段树不断扩大范围并更新。随机一个 1 ~ n 的序列利用线段树更新,这样速度会变得很快,或其他优化方法均可(这里采用sin函数排序差不多就无序了= =)。还有就是注意题目是按原来的i输出,我因为这个被卡了一下午,MDZZ。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x3f3f3f3f
const int mx=1e5+10;
typedef long long ll;
int n,sum[mx<<2][2],a[mx],ans[mx],b[mx];
using namespace std;
struct sec{
int l,r;
bool operator < (sec A)const{
return l<A.l;
}
sec() {}
sec(int ll,int rr){ l=ll,r=rr; }
}s[mx],po[mx];
bool cmp(int a,int b){
return sin(1.0*a)<sin(1.0*b);
}
void build(int l,int r,int rt){
if(l==r){
sum[rt][0]=s[l].l;
sum[rt][1]=s[l].r;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
sum[rt][0]=min(sum[rt<<1][0],sum[rt<<1|1][0]);
sum[rt][1]=max(sum[rt<<1][1],sum[rt<<1|1][1]);
}
sec query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r){
return sec(sum[rt][0],sum[rt][1]);
}
int m=(l+r)>>1;
sec num[2]={{inf,0},{inf,0}};
if(m>=L) num[0]=query(L,R,lson);
if(R>m) num[1]=query(L,R,rson);
return sec( min(num[0].l,num[1].l) , max(num[0].r,num[1].r) );
}
void update(int L,int R,int l,int r,int rt,int vl,int vr){
if(l==r){
sum[rt][0]=min(vl,sum[rt][0]);
sum[rt][1]=max(vr,sum[rt][1]);
return ;
}
int m=(l+r)>>1;
if(m>=L) update(L,R,lson,vl,vr);
if(R>m) update(L,R,rson,vl,vr);
sum[rt][0]=min(sum[rt<<1][0],sum[rt<<1|1][0]);
sum[rt][1]=max(sum[rt<<1][1],sum[rt<<1|1][1]);
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%d%d",&s[i].l,&s[i].r);
po[i].l=s[i].l ,po[i].r=i;
}a[n+1]=-inf;
sort(s+1,s+1+n);
sort(po+1,po+1+n);
for(int i=1;i<=n;i++) a[i]=s[i].l;
for(int i=1;i<=n;i++){
int l=s[i].l,r=s[i].r;
s[i].l=lower_bound(a+1,a+1+n,l-r)-a;
s[i].r=lower_bound(a+1,a+1+n,l+r)-a;
if(a[s[i].r]!=l+r) s[i].r--;
}
build(1,n,1);
for(int i=1;i<=n;i++) a[i]=i;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
int id=0,t=a[i];
sec num[2]={{t,t},{0,0}};
while(num[0].l!=num[1].l || num[0].r!=num[1].r){
num[id^1]=query(num[id].l,num[id].r,1,n,1);
id^=1;
}
update(t,t,1,n,1,num[id].l,num[id].r);//更新t点感染范围
ans[po[t].r]=num[id].r-num[id].l+1;//找回原来的位置赋值
}printf("%d",ans[1]);
for(int i=2;i<=n;i++) printf(" %d",ans[i]);
puts("");
}
return 0;
}