实验室传染病
Time limit per test: 2.0 seconds
Time limit all tests: 10.0 seconds
Memory limit: 256 megabytes
ECNU 的 ACM 实验室患上了一种传染病,这种病的传染性极强,并且因为每个人的体质不同传染的范围也不同。
为了简化这个问题,我们不妨假设有 n 个人站在一条水平线上,每个人有初始的位置和他患病时的传染范围。当一个人患病时,他的传染范围内(包括边界上)的人全部会被感染并继续向外传播。
但是我们并不知道 ECNU 实验室的传染源是谁,所以请你计算出每个人作为传染源时最后会使得多少人被感染?
Input
测试数据包含不超过 20 个测试文件,每个测试文件是单组数据。
第一行一个整数 n (1≤n≤105)。
接下来 n 行每行有两个整数 xi,ri (−109≤xi≤109,1≤ri≤109),表示每个人的位置和传染范围。
数据保证位置各不相同。
Output
一行 n 个整数。其中第 i 个表示第 i 个人(按照输入顺序)作为传染源时最后被感染的人数。
Examples
input
4 0 10 8 3 18 10 20 1
output
2 1 3 1
Source
2017 华东师范大学网赛 解:主要思想就是不断更新左右区间;更新1:如果当前点的做范围的点的左边界大于他的左边界就一直更新,右边界同理: 更新2:当前的点虽然左范围覆盖不到左边的点但是可以通过右边界能够覆盖到的点去覆盖左边界;重复更新,直到无法更新
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
typedef long long LL;
typedef pair<int,int>pi;
int l[N], r[N];
pi a[N], b[N];
int flag, n;
void update1()
{
stack<LL>st;
for(int i=1;i<=n;i++)
{
while(!st.empty()&&st.top()>=l[i])
{
if(l[st.top()]<l[i])
{
l[i]=l[st.top()];
flag=1;
}
st.pop();
}
st.push(i);
}
stack<LL>st2;
for(int i=n;i>=1;i--)
{
while(!st2.empty()&&st2.top()<=r[i])
{
if(r[st2.top()]>r[i])
{
r[i]=r[st2.top()];
flag=1;
}
st2.pop();
}
st2.push(i);
}
return ;
}
void update2()
{
stack<LL>st;
for(int i=1;i<=n;i++)
{
while(!st.empty()&&st.top()>=l[i])
{
if(r[st.top()]>r[i])
{
r[i]=r[st.top()];
flag=1;
}
st.pop();
}
st.push(i);
}
stack<LL>st2;
for(int i=n;i>=1;i--)
{
while(!st2.empty()&&st2.top()<=r[i])
{
if(l[st2.top()]<l[i])
{
l[i]=l[st2.top()];
flag=1;
}
st2.pop();
}
st2.push(i);
}
return ;
}
int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[i].first,&a[i].second);
b[i]=a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
l[i]=(int)(lower_bound(a+1,a+n+1,make_pair(a[i].first-a[i].second,0))-(a));
r[i]=(int)(lower_bound(a+1,a+n+1,make_pair(a[i].first+a[i].second,0x3f3f3f3f))-(a+1));
}
while(1)
{
flag=0;
update1();
update2();
if(flag==0) break;
}
for(int i=1;i<=n;i++)
{
int k=(int)(lower_bound(a+1,a+n+1,b[i])-a);
printf("%d%c",r[k]-l[k]+1,i==n?'\n':' ');
}
}
return 0;
}