熟悉啊各位,看到这题的时候有没有一种TMD绝壁看过但就是不会做的感觉啊?!!
比赛的时候G题蜜汁精度又WA又T38发,最后也没有好好想这道题,赛后好好考虑了一下,其实思路挺清晰的,不过还是又一些坑点,又WA又T了好多发才过 TAT,解法也是玄学啊。
思路:
大致的思路就是,预先处理出每个点一次扩展能到达的范围,代码中用
far_l[],far_r[]
表示,然后用一个线段树维护每个区间的往左往右最多能感染的范围。
一开始线段树里先放入扩展一次的左右点,然后维护。
对于点
i
的查询,一开始假设感染区间为为
不断重复上述扩增操作,直到不能再扩增了位置。
假设得到
answer[i]=[l,r]
需要把这个点在线段树上包含这个点的区间更新为
[l,r]
,因为如果你不更新要不然直接出
{i,1}
这样一组数据就直接炸了。
但是以为这样就可以了吗? 并不!
还是有数据可以卡你,死活T在一组数据上!虽然我也不知道数据到底是什么,但是可以想到可能是类似于有序序列对于
QSort
一样被卡死,所以
shuffle
一下。
done.
思路:
#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' : ' ');
}
}