题解 CF609F 【Frogs and mosquitoes】
Clever_Jimmy · · 题解
题意简述
给定数轴非负半轴上的
每只蚊子
问最后每只青蛙吃掉的蚊子的数量以及最后每只青蛙舌头的长度[^1]。
数据范围:
解题思路
我们实际上要解决的问题,是每只蚊子落下来了之后,被哪只青蛙吃掉。
首先离散化,然后维护区间中
注意到一只蚊子可能落下来的时候没有青蛙能吃到,但是之后某只青蛙的舌头变长了,能吃到它了;因此我们需要一个 multiset 来维护没吃掉的蚊子。
当在线段树上位于一个 multiset 里存着以后吃。
如果当前节点满足
- 如果
\textrm{dat}(2p) \ge p_i ,即左儿子节点有青蛙可以吃掉这只蚊子,那肯定是优先选更靠左的青蛙吃掉,向左儿子递归; - 否则如果
\textrm{dat}(2p + 1) \ge p_i ,即右儿子节点有青蛙可以吃掉这只蚊子,那就往右儿子递归。 - 如果到了一个叶子节点,说明这个节点表示的青蛙要吃掉当前蚊子了,更新
l_i ,\textrm{eat}(p) (表示这只青蛙吃了多少只蚊子)以及\textrm{dat}(p) 。
在更新 multiset 里能不能吃更多的蚊子;实现上就是在 multiset 里 lower_bound,找
代码实现
#include <bits/stdc++.h>
#define LL long long
namespace io {
template <typename T> inline void read(T & _x) {
int f = 0, ch; _x = 0;
while(!isdigit(ch = getchar())) f |= ch == '-';
while(isdigit(ch)) _x = _x * 10 + ch - '0', ch = getchar();
if(f) _x = -_x;
}
template <typename T, typename ... Args> inline void read(T &_f, Args& ... args) {
read(_f), read(args ...);
}
inline void _deal(char ch) { putchar(ch); }
template <typename T> inline void _deal(T _x) {
if (_x < 0) putchar('-'), _x = -_x;
if (_x > 9) _deal(_x / 10);
putchar(_x % 10 + '0');
}
inline void write() {}
template <typename T, typename ... Args> inline void write(T _f, Args ... args) {
_deal(_f), write(args...);
}
}
const int N = 2e5 + 5;
const int M = 2e5 + 5;
int n, m, x[N], t[N], rk[N];
std::multiset<std::pair<int, int> > ms;
std::pair<int, LL> ans[M];
bool cmp(int aa, int bb) {
return x[aa] < x[bb];
}
struct SEGTREE {
static const int MS = N * 4;
LL dat[MS];
int eat[MS], frm[MS];
void pushup(int p) {
dat[p] = std::max(dat[p << 1], dat[p << 1 | 1]);
}
void build(int p, int L, int R) {
if(L == R) {
dat[p] = x[rk[L]] + t[rk[L]];
eat[p] = 0;
frm[p] = x[rk[L]];
return;
}
int MID = L + R >> 1;
build(p << 1, L, MID), build(p << 1 | 1, MID + 1, R);
pushup(p);
}
void solve(int p, int L, int R, int pos, int siz) {
if(dat[p] < pos) {
ms.insert(std::make_pair(pos, siz));
return;
}
if(L == R) {
if(frm[p] > pos)
ms.insert(std::make_pair(pos, siz));
else {
dat[p] += siz, ++eat[p];
for(std::multiset<std::pair<int, int> >::iterator it = ms.lower_bound(std::make_pair(frm[p], -1)); it != ms.end();) {
if(it->first > dat[p])
break;
else {
dat[p] += it->second;
++eat[p];
std::multiset<std::pair<int, int> >::iterator tmp = it;
++it;
ms.erase(tmp);
}
}
}
return;
}
int MID = L + R >> 1;
if(dat[p << 1] >= pos)
solve(p << 1, L, MID, pos, siz);
else if(dat[p << 1 | 1] >= pos)
solve(p << 1 | 1, MID + 1, R, pos, siz);
pushup(p);
}
std::pair<int, LL> query(int p, int L, int R, int x) {
if(L == R)
return std::make_pair(eat[p], dat[p] - frm[p]);
int MID = L + R >> 1;
if(x <= MID)
return query(p << 1, L, MID, x);
else
return query(p << 1 | 1, MID + 1, R, x);
}
} tr;
int32_t main() {
io::read(n, m);
for(int i = 1; i <= n; ++i) {
io::read(x[i], t[i]);
rk[i] = i;
}
std::sort(rk + 1, rk + n + 1, cmp);
tr.build(1, 1, n);
for(int i = 1; i <= m; ++i) {
int ttp, ttb;
io::read(ttp, ttb);
tr.solve(1, 1, n, ttp, ttb);
}
for(int i = 1; i <= n; ++i)
ans[rk[i]] = tr.query(1, 1, n, i);
for(int i = 1; i <= n; ++i)
printf("%d %lld\n", ans[i].first, ans[i].second);
return 0;
}
原题链接: F. Frogs and mosquitoes