EOJ 3246 实验室传染病 线段树

来源:互联网 发布:极乐净土三人动作数据 编辑:程序博客网 时间:2024/06/06 19:45

题目:

http://acm.ecnu.edu.cn/problem/3246/

题意:

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

思路:

对所有人按坐标从小到大排序,每个人视为一个点。首先二分处理出每个点单次传播的范围,即求出传播区间的左端的人代表的点和右端的人代表的点,然后建线段树,每个人作为一个点,每个点维护它传播范围的左端点和右端点。对于以一个人为传染源所能传播的最大范围,我们每次求出其当前传播范围内的点所能传播的范围,其实就是把当前范围尽量向左向右扩展,一直重复扩展,直到不能扩展位置,就是答案。

#include <bits/stdc++.h>using namespace std;typedef pair<int, int> P;const int N = 100000 + 10, INF = 0x3f3f3f3f;struct node{    int l, r, fl, fr;//fl,fr是传播范围的左右端点}seg[N*4];struct pnode{    int a, b, id;}arr[N];int fl[N], fr[N], tmp[N], ans[N];bool cmp(const pnode x, const pnode y){    return x.a < y.a;}void push_up(int k){    seg[k].fl = min(seg[k<<1].fl, seg[k<<1|1].fl);    seg[k].fr = max(seg[k<<1].fr, seg[k<<1|1].fr);}void build(int l, int r, int k){    seg[k].l = l, seg[k].r = r;    if(l == r)    {        seg[k].fl = fl[l], seg[k].fr = fr[l];        return;    }    int mid = (l + r) >> 1;    build(l, mid, k << 1);    build(mid+1, r, k << 1|1);    push_up(k);}void update(int fl, int fr, int x, int k){    if(seg[k].l == seg[k].r)    {        seg[k].fl = fl, seg[k].fr = fr;        return;    }    int mid = (seg[k].l + seg[k].r) >> 1;    if(x <= mid) update(fl, fr, x, k << 1);    else update(fl, fr, x, k << 1|1);    push_up(k);}P work(int l, int r, int k)//向左向右扩展其传播区间{    if(l <= seg[k].l && seg[k].r <= r)    {        return make_pair(seg[k].fl, seg[k].fr);    }    int mid = (seg[k].l + seg[k].r) >> 1;    P p1(INF, -INF), p2(INF, -INF);    if(l <= mid) p1 = work(l, r, k << 1);    if(r > mid) p2 = work(l, r, k << 1|1);    return make_pair(min(p1.first, p2.first), max(p1.second, p2.second));}P query(int x){    P p = make_pair(fl[x], fr[x]), res;    while(true)    {        res = work(p.first, p.second, 1);        if(p == res) break;        p = res;    }    update(p.first, p.second, x, 1);    return p;}int main(){    int n;    scanf("%d", &n);    for(int i = 1; i <= n; i++)    {        scanf("%d%d", &arr[i].a, &arr[i].b);        arr[i].id = i;        tmp[i] = arr[i].a;    }    sort(arr+1, arr+1+n, cmp);    sort(tmp+1, tmp+1+n);    for(int i = 1; i <= n; i++)    {        fl[i] = lower_bound(tmp+1, tmp+1+n, arr[i].a - arr[i].b) - tmp;        fr[i] = lower_bound(tmp+1, tmp+1+n, arr[i].a + arr[i].b) - tmp;        while(fr[i] > n || (arr[fr[i]].a > arr[i].a + arr[i].b && fr[i] > 0)) fr[i]--;    }    build(1, n, 1);    for(int i = 1; i <= n; i++) tmp[i] = i;    random_shuffle(tmp+1, tmp+1+n);    for(int i = 1; i <= n; i++)    {        P p = query(tmp[i]);        ans[arr[tmp[i]].id] = p.second - p.first + 1;    }    for(int i = 1; i <= n; i++) printf("%d%c", ans[i], i == n ? '\n' : ' ');    return 0;}
原创粉丝点击