题意
- 有n青蛙和m蚊子(n,m<=1e5),青蛙两个参数,位置xi,舌头长度ti
- 蚊子两个参数,位置pj,权值bj
- 只有当xi+ti>=pj且xi <= pj时,第i只青蛙才能吃到第j只蚊子。
- 如果第j只蚊子能被多只青蛙吃到,那么xi最小的青蛙会把这只蚊子吃了
- 每次青蛙吃了某只蚊子以后,ti会增加蚊子的bj
- 蚊子会按输入的顺序到来,如果没一下没吃掉,蚊子还是会落在原位不动,即蚊子有可能之后被吃掉
- 输出n只青蛙吃的蚊子数,以及最后时候的舌头长度ti
思路
- 先考虑每来一只蚊子时,我们怎么找到是哪只青蛙吃掉的呢?
- 是不是找到,最左的位置l,使得[0, l]里青蛙xi + ti的最大值 > 蚊子位置pj, 并且xi <= pj即可
- 由于位置l,和[0,l]中最大值有单调关系所以,我们通过二分很容易找到位置l
- 另一方面,吃的青蛙,舌头会变长,即存在点修改和刚才说得区间查询,即用线段树可解
- 随便一想,可能会觉得用位置做下标建树挺好,但是呢,位置到1e9,存不下,所以简单离散化一下,把青蛙按照xi进行排序,以青蛙数组下标建树,维护xi+ti的最大值,然后二分青蛙数组的下标即可。
- 最后注意:蚊子是有可能之后被吃掉的!所以呢,还需要维护没被吃掉蚊子的位置
- 这里,不难想到,用平衡二叉搜索树(multimap)解决即可。注意:一定是mutimap,因为蚊子可以落在同一点上!我被这点坑半天。。。
实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+6;
multimap<int,int> mapp;
ll maxv[3*maxn];
struct Node{
int x, id;
ll sum;
}a[maxn];
ll init(int v,int l,int r){
if (l == r){
maxv[v] = a[l].sum;
return a[l].sum;
}
int chl = 2*v+1, chr = 2*v+2, mid = (l+r) / 2;
maxv[v] = max(init(chl, l, mid), init(chr, mid+1, r));
return maxv[v];
}
ll query(int u,int l,int r, int x1, int x2){
if (x2 < l || x1 > r){
return 0;
}
if (x1 <= l && x2 >= r){
return maxv[u];
}
int chl = 2*u+1, chr = 2*u+2, mid = (l+r) / 2;
return max(query(chl, l, mid,x1,x2), query(chr, mid+1, r, x1, x2));
}
ll add(int u,int l,int r,int x,int y){
if (l == r){
a[x].sum += (ll)y;
maxv[u] += (ll)y;
return maxv[u];
}
int chl = 2*u+1, chr = 2*u+2, mid = (l+r) / 2;
if (x <= mid){
return maxv[u] = max(maxv[u], add(chl, l, mid, x, y));
}
else{
return maxv[u] = max(maxv[u], add(chr, mid+1, r, x , y));
}
}
bool cmp(Node x, Node y){
return x.x < y.x;
}
int num[maxn];
ll len[maxn];
int n,m;
int main(){
scanf("%d%d",&n,&m);
for (int i = 0;i < n;i++){
int x,l;
scanf("%d%d",&x, &l);
a[i].sum = (ll)x + (ll)l;
len[i] = (ll)l;
a[i].x = x;
a[i].id = i;
}
sort(a,a+n,cmp);
init(0, 0, n-1);
for (int t=0; t < m;t++){
int p,b;
scanf("%d%d",&p,&b);
int low = 0, high = n - 1;
int ans = -1;
while (low <= high){
int mid = (low + high) / 2;
if (query(0, 0, n-1, 0, mid) >= p){
high = mid - 1;
ans = mid;
}
else{
low = mid + 1;
}
}
if (ans == -1 || a[ans].x > p){
mapp.insert(make_pair(p,b));
continue;
}
num[a[ans].id]++;
len[a[ans].id] += (ll)b;
add(0, 0, n-1, ans, b);
auto it = mapp.lower_bound(a[ans].x);
while (it != mapp.end() && it->first <= a[ans].sum){
num[a[ans].id]++;
len[a[ans].id] += (ll)it->second;
add(0, 0, n-1, ans, it->second);
auto tmp = it;
it++;
mapp.erase(tmp);
}
}
for(int i=0;i<n;i++){
printf("%d %I64d\n",num[i],len[i]);
}
return 0;
}