特别玄学的一道题
来源:互联网 发布:卖淘宝小号的平台 编辑:程序博客网 时间:2024/04/30 03:38
点击打开链接
题意:给你n个点,每个点有一个以他自身为中心的范围,求每个数能扩散的最大范围,扩散具有传递性!
官方题解:
很多人的做法是先对每个点找出最右边传染病可以到达的位置,再找出最左边可以达到的位置,然后二者相减。
这样做很明显的问题是你最右边可以达到的位置可能是在你左边的人所传染的。
一种做法是可以二分预处理出来每个点单次传染到的左右范围,再用线段树维护每个点最终的范围最小值、最大值,利用线段树不断扩大范围并更新。你可以随机一个
这里提供另一种很奇怪的方法:从左往右扫,用一个 latest 保证一个点只计算一次。在计算每个点的过程中,先把当前点的影响范围暂存为它左边影响的点的影响范围并上它本身的影响范围。然后对它本身影响范围内的点没有计算过的进行递归计算,计算完了之后重新统计。
很容易产生的一个问题就是如果递归的点计算需要这个点的数据怎么办?我们认为这种情况是不影响的。因为事实上,这个点的数据之所以不对是因为它后面的点还没有进行计算。我们会把后面的点都并到正在计算的点的计算范围,然后我们还是会对后面的点进行计算。
同样用线段树维护查询。
所以每次o(n)去递推每个点的最左和最右,然后再考虑左右影响log(n)次即可。
不知道这是什么定理,但是的确对。也可能这题数据水,只左右t贪心扫两次都可以过题。
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<set>#include<map>#include<string>using namespace std;typedef long long ll;typedef pair<int,int> P;const int INF=0x3f3f3f3f;int n;P a[100010],b[100010];int l[100010],r[100010];void solve1(){ stack<int>s; for(int i=1;i<=n;i++) { while(!s.empty()&&s.top()>=l[i]) { l[i]=min(l[i],l[s.top()]); s.pop(); } s.push(i); } while(!s.empty())s.pop(); for(int i=n;i>=1;i--) { while(!s.empty()&&s.top()<=r[i]) { r[i]=max(r[i],r[s.top()]); s.pop(); } s.push(i); }}void solve2(){ stack<int>s; for(int i=1;i<=n;i++) { while(!s.empty()&&s.top()>=l[i]) { r[i]=max(r[i],r[s.top()]); s.pop(); } s.push(i); } while(!s.empty())s.pop(); for(int i=n;i>=1;i--) { while(!s.empty()&&s.top()<=r[i]) { l[i]=min(l[i],l[s.top()]); s.pop(); } s.push(i); }}int main(){ scanf("%d",&n); 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]=lower_bound(a+1,a+1+n,P(a[i].first-a[i].second,-1))-a; r[i]=lower_bound(a+1,a+1+n,P(a[i].first+a[i].second,INF))-a-1; } for(int i=1;i<=17;i++)//看似是n^2,实际只需要更新logn次就足够了,不知道这是什么定理,但是的确是对的! solve1(),solve2(); for(int i=1;i<=n;i++) { int pos=lower_bound(a+1,a+n+1,b[i])-a; printf("%d%c",r[pos]-l[pos]+1,i==n?'\n':' '); } return 0;}
正规解:
#include <set>#include <map>#include <queue>#include <cmath>#include <vector>#include <cstdio>#include <utility>#include <cstring>#include <iostream>#include <algorithm>const int maxn = 100007;int far_l[maxn], far_r[maxn], n;struct SegTree{ int l, r, far_l, far_r;}seg[maxn * 4];void build(int l, int r, int k){ seg[k].l = l; seg[k].r = r; if(l == r) { seg[k].far_l = far_l[l]; seg[k].far_r = far_r[r]; return; } int mid = (l + r) / 2; build(l, mid, 2 * k); build(mid + 1, r, 2 * k + 1); seg[k].far_l = std::min(seg[2*k].far_l, seg[2*k+1].far_l); seg[k].far_r = std::max(seg[2*k].far_r, seg[2*k+1].far_r);}std::pair<int, int> cal(int l, int r, int k){ if(l <= seg[k].l && seg[k].r <= r) { return {seg[k].far_l, seg[k].far_r}; } int mid = (seg[k].l + seg[k].r) / 2; if(r <= mid) { return cal(l, r, 2*k); } else if(l > mid) { return cal(l, r, 2*k+1); } else { auto a = cal(l, mid, 2*k); auto b = cal(mid+1, r, 2*k+1); return {std::min(a.first, b.first), std::max(a.second, b.second)}; }}void update(int t, int k, int l, int r){ if(seg[k].l == seg[k].r) { seg[k].far_l = l; seg[k].far_r = r; return; } int mid = (seg[k].l + seg[k].r) / 2; if(t <= mid) update(t, 2*k, l, r); else update(t, 2*k+1, l, r); seg[k].far_l = std::min(seg[2*k].far_l, seg[2*k+1].far_l); seg[k].far_r = std::max(seg[2*k].far_r, seg[2*k+1].far_r);}std::pair<int,int> query(int t){ int l = far_l[t], r = far_r[t]; int count = 0; while(true) { auto rec = cal(l, r, 1); if(l == rec.first && r == rec.second) break; l = rec.first, r = rec.second; count ++; } update(t, 1, l, r); return {l, r};}struct Node{ int a, b, id;}node[maxn];int ans[maxn];bool cmp(const Node &_a, const Node &_b){ return _a.a < _b.a;}int Scan()///输入外挂{ int res=0,ch,flag=0; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0'; return flag?-res:res;}int main(){ n = Scan(); for(int i = 1; i <= n; i ++) { node[i].a = Scan(); node[i].b = Scan(); node[i].id = i; } std::sort(node+1, node+n+1, cmp); for(int i = 1; i <= n; i ++) { int l = i, r = n; while(l <= r) { int mid = (l + r) / 2; if(node[mid].a - node[i].a <= node[i].b) { far_r[i] = mid; l = mid + 1; } else r = mid - 1; } } for(int i = 1; i <= n; i ++) { int l = 1, r = i; while(l <= r) { int mid = (l + r) / 2; if(node[i].a - node[mid].a <= node[i].b) { far_l[i] = mid; r = mid - 1; } else l = mid + 1; } } build(1, n, 1); std::vector<int> vec; for(int i = 1; i <= n; i ++) { vec.push_back(i); } std::random_shuffle(vec.begin(), vec.end()); for(int i = 0; i < n; i ++) { int id = vec[i]; auto k = query(id); k = cal(k.first, k.second, 1); ans[node[id].id] = k.second - k.first + 1; } for(int i = 1; i <= n; i ++) { printf("%d%c", ans[i], i == n ? '\n' : ' '); }}
阅读全文
0 0
- 特别玄学的一道题
- HDU-5835 一道特别简单的题
- 玄学
- 一道微软2013实习生招聘题(c++,特别容易出错)
- 京东运维的玄学值面试
- 树状数组的玄学功效
- 星星 不知名的玄学看图题
- UVA1515 pool ,玄学的最小割
- 很玄学的最大流(模板)
- 特别特别繁忙的九月
- 一道C的题
- microsoft的一道题
- 指针的一道题
- 解谷歌的一道题
- 一道有趣的题
- 有意思的一道题
- 一道题引发的。。。。。
- JS的一道题
- 《软技能--代码之外的生存指南》————第三篇---学习
- InnoDB存储引擎读书笔记
- DQN
- 【JavaScript】(8)JavaScript中的正则表达式创建方式、基础语法、及其compile | exec | test 方法
- MySQL 管理
- 特别玄学的一道题
- 结构体字节对齐
- 深度学习笔记——Word2vec和Doc2vec训练实例以及参数解读
- 说说JSON和JSONP,也许你会豁然开朗
- cookies过多导致的http400 Bad Request异常
- POJ.1061 青蛙的约会 (拓展欧几里得)
- SQl server 2008 r2 迅雷下载地址
- 文章标题
- iconFont在iOS上的使用详解