codeforces 609F Frogs and mosquitoes 线段树+二分+multiset

54 篇文章 0 订阅
42 篇文章 0 订阅

http://codeforces.com/problemset/problem/609/F
There are n frogs sitting on the coordinate axis Ox. For each frog two values xi, ti are known — the position and the initial length of the tongue of the i-th frog (it is guaranteed that all positions xi are different). m mosquitoes one by one are landing to the coordinate axis. For each mosquito two values are known pj — the coordinate of the position where the j-th mosquito lands and bj — the size of the j-th mosquito. Frogs and mosquitoes are represented as points on the coordinate axis.

The frog can eat mosquito if mosquito is in the same position with the frog or to the right, and the distance between them is not greater than the length of the tongue of the frog.

If at some moment several frogs can eat a mosquito the leftmost frog will eat it (with minimal xi). After eating a mosquito the length of the tongue of a frog increases with the value of the size of eaten mosquito. It's possible that after it the frog will be able to eat some other mosquitoes (the frog should eat them in this case).

For each frog print two values — the number of eaten mosquitoes and the length of the tongue after landing all mosquitoes and after eating all possible mosquitoes by frogs.

Each mosquito is landing to the coordinate axis only after frogs eat all possible mosquitoes landed before. Mosquitoes are given in order of their landing to the coordinate axis.

Input

First line contains two integers n, m (1 ≤ n, m ≤ 2·105) — the number of frogs and mosquitoes.

Each of the next n lines contains two integers xi, ti (0 ≤ xi, ti ≤ 109) — the position and the initial length of the tongue of the i-th frog. It is guaranteed that all xi are different.

Next m lines contain two integers each pj, bj (0 ≤ pj, bj ≤ 109) — the position and the size of the j-th mosquito.

Output

Print n lines. The i-th line should contain two integer values ci, li — the number of mosquitoes eaten by the i-th frog and the length of the tongue of the i-th frog.

Examples
Input

4 6
10 2
15 0
6 1
0 1
110 10
1 1
6 0
15 10
14 100
12 2

Output

3 114
1 10
1 1
1 2

Input

1 2
10 2
20 2
12 1

Output

1 3

题目大意:给出 n n n只青蛙的位置 p o s 1 pos1 pos1和舌头长度 l e n len len,给出 m m m只蚊子的位置 p o s 2 pos2 pos2 s i z e size size,认为青蛙和蚊子都在一条线上且把它们当成点来处理,如果满足条件: p o s 1 &lt; = p o s 2 &lt; = p o s 1 + l e n pos1&lt;=pos2&lt;=pos1+len pos1<=pos2<=pos1+len,则这只蚊子可以被青蛙吃掉,同时青蛙的舌头长度变为: l e n + = s i z e len+=size len+=size。蚊子是按照顺序一只一只的落在线上的,当且仅当前面的蚊子都已经被吃掉了或者无法被吃掉,下一只蚊子才会落下来。而且如果有多只青蛙能吃到该蚊子,则一定是最左侧的青蛙吃掉该蚊子。请输出每只青蛙最终吃掉的蚊子数量 a n s ans ans以及舌头的最终长度 l e n len len
思路:半年前看不懂题解的题现在终于能看懂题解了。对于每只蚊子要选择能吃掉它的且最靠左的青蛙,怎么求这只青蛙呢。首先我们需要把青蛙按照坐标从小到大排序,然后我们用线段树维护 p o s 1 + l e n pos1+len pos1+len的最大值,那么我们需要找到一个最小的 i i i满足 q u e r y ( 1 , i ) &gt; = p o s 2 query(1,i)&gt;=pos2 query(1,i)>=pos2。( q u e r y ( 1 , i ) query(1,i) query(1,i)表示查询排序后第 1 1 1只青蛙到第 i i i只青蛙的 p o s 1 + l e n pos1+len pos1+len的最大值)线段树+二分可以找到这个 i i i。但是题目给的坐标范围太大了,因此我们需要离散一下,记录一下每只青蛙的初始下标 i n d e x index index就好了。对于每只蚊子,我们先判断一下它能不能被吃掉,如果不能的话就把他的位置记录在 m u l t i s e t multiset multiset中(因为可能有多只蚊子在同一位置),如果能吃掉的话,就更新 a n s ans ans l e n len len,同时还要判断这只青蛙的舌头变长后是不是能吃掉原来吃不到的青蛙。如果能的话,继续更新下去就好了。详见代码注释。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define pr pair<long,long>
using namespace std;
typedef long long ll;

const int maxn=2e5+5;

struct node
{
    ll pos,len;
    int id;
    bool operator <(const node &a)const
    {
        return pos<a.pos;
    }
}a[maxn];

struct T
{
    int l,r;
    ll MAX;
}tree[maxn<<2];
pr mos[maxn];//记录蚊子的坐标和size
int ans[maxn];//记录青蛙吃到的蚊子数量
ll len[maxn];//记录青蛙的舌头长度
ll x[maxn];//记录青蛙的坐标
int n,m;

void build(int i,int l,int r)
{
    tree[i].l=l,tree[i].r=r;
    if(l==r)
    {
        tree[i].MAX=a[l].pos+a[l].len;
        return ;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    tree[i].MAX=max(tree[i<<1].MAX,tree[i<<1|1].MAX);
}

ll query(int i,int l,int r)
{
    if(tree[i].l==l&&tree[i].r==r)
        return tree[i].MAX;
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        return query(i<<1,l,r);
    else if(l>mid)
        return query(i<<1|1,l,r);
    else
        return max(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
}

void update(int i,int pos,ll v)
{
    if(tree[i].l==tree[i].r)
    {
        tree[i].MAX+=v;
        return ;
    }
    int mid=(tree[i].l+tree[i].r)>>1;
    if(pos<=mid)
        update(i<<1,pos,v);
    else
        update(i<<1|1,pos,v);
    tree[i].MAX=max(tree[i<<1].MAX,tree[i<<1|1].MAX);
}

int solve(ll pos)//找能吃到pos这个位置的蚊子的最左侧的青蛙
{
    int l=1,r=upper_bound(x+1,x+1+n,pos)-x-1;
    if(r==0||query(1,1,r)<pos)//吃不到
        return -1;
    int mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(query(1,1,mid)<pos)
            l=mid+1;
        else
            r=mid-1;
    }
    return l;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&a[i].pos,&a[i].len),a[i].id=i;
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
        x[i]=a[i].pos;
    for(int i=1;i<=m;i++)
        scanf("%lld%lld",&mos[i].first,&mos[i].second);
    build(1,1,n);
    multiset<pr> s;
    for(int i=1;i<=m;i++)
    {
        int pos=solve(mos[i].first);
        if(pos==-1)//暂时没有青蛙能吃到这只蚊子
            s.insert(mos[i]); //插入到set集合中
        else//有青蛙能吃到这只蚊子
        {
            ans[a[pos].id]++;//记录这只青蛙吃到的蚊子数量
            a[pos].len+=mos[i].second;//青蛙的舌头长度增加
            update(1,pos,mos[i].second);
            ll tmp=a[pos].pos+a[pos].len;//这只青蛙能吃到的最靠右侧的蚊子
            while(!s.empty())//看这只青蛙是不是能吃到以前不能吃到的蚊子
            {
                multiset<pr>:: iterator it=s.lower_bound(pr(a[pos].pos,0));//找到在这只青蛙右侧的第一只蚊子
                if(it==s.end()||it->first>tmp)//没有找到或者这只蚊子太远了 还是吃不到
                    break;
                tmp+=it->second;//该青蛙现在能吃到这只蚊子了
                ans[a[pos].id]++;//更新数量
                a[pos].len+=it->second;//更新长度
                update(1,pos,it->second);
                s.erase(it);//从set中删去这只蚊子
            }
        }
    }
    for(int i=1;i<=n;i++)
        len[a[i].id]=a[i].len;
    for(int i=1;i<=n;i++)
        printf("%d %lld\n",ans[i],len[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值