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;}
阅读全文
0 0
- EOJ 3246 实验室传染病 线段树
- EOJ 3246实验室传染病(单调栈)@
- EOJ-大学生程序设计邀请赛(华东师范大学)-D-实验室传染病
- 2017 ECNU 网赛 D. 实验室传染病
- 传染病?!
- 【最小生成树】传染病防疫
- EOJ 1813 树重建
- EOJ 1815 Huffman树
- EOJ
- EOJ
- EOJ
- EOJ 2067 最小生成树
- EOJ 1811 树的遍历
- EOJ 1814 完全二叉树?
- EOJ-3261 字典树 + dp
- 【NOIp 2003】【树结构·搜索】传染病防治
- 传染病数学模型
- 传染病控制
- 欢迎使用CSDN-markdown编辑器
- Linux安装tomcat
- 单向链表
- 河南省第十届ACM 省赛 A 谍报分析
- Linux交叉编译环境搭建和内核编译
- EOJ 3246 实验室传染病 线段树
- redisutil spring session 响应创建和摧毁
- java 方法参数-值调用,引用调用问题
- ML算法工程师的三个层次
- centos php7 安装mysqli扩展心得
- SystemInfo类-Unity(转载)
- gson解析泛型数据
- Kotlin学习笔记(四)-函数补充
- 自定义Dialog