题意
有 (n) 只位置互不相同青蛙,第 (i) 只青蛙位置为 (x_i),舌头长度为 (t_i),能吃到 ([x_i,x_i+t_i]) 范围内的蚊子。
有 (m) 只蚊子依次出现,位置为 (p_j) (可能重复),价值为 (b_j),它会被能吃掉它的最左边的青蛙吃掉,吃完它后那只青蛙的舌头长度会增长 (b_j)。
只有已经出现的蚊子都被吃了或者无法被吃掉时,新的蚊子会出现。
问每只青蛙吃掉了多少只蚊子及最终的舌头长度。
(1 le n,m le 10^5),(0 le x_i,t_i,p_i,b_i le 10^9)
思路
将青蛙按位置排序,建一棵 (x_i+t_i) 的线段树,对于一直蚊子,在线段树上二分找到最左边的大于他位置的青蛙,判断一下青蛙的初始位置有没有超过蚊子。
如果没有能吃掉它的青蛙,就存储起来。
当一只青蛙舌头变长的时候,更新线段树,并回头查查有没有原先的蚊子能被吃掉,所以存储的用 (multiset) 每次去二分就可以了。
#include <bits/stdc++.h>
using std::pair;
using std::make_pair;
using std::multiset;
#define mp make_pair
#define fi first
#define se second
const int N=200005;
typedef long long ll;
typedef pair<ll,int> pli;
typedef multiset<pli>::iterator it;
multiset<pli> s;
ll t[N<<2];
int n,m,ans[N],x,siz;
struct frog{
int pos,id;
ll l;
}a[N];
bool cmp(frog x,frog y){
return x.pos<y.pos;
}
void push_up(int x){
t[x]=std::max(t[x<<1],t[x<<1|1]);
}
void build(int k,int l,int r){
if (l==r){
t[k]=a[l].pos+a[l].l;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
push_up(k);
}
int query(int k,int l,int r,int x){
if (t[k]<x) return -1;
if (l==r){
if (a[l].pos>x) return -1;
return l;
}
int mid=(l+r)>>1;
if (t[k<<1]>=x) return query(k<<1,l,mid,x);
return query(k<<1|1,mid+1,r,x);
}
void modify(int k,int l,int r,int x,int y){
if (l==r){
t[k]+=y;
return;
}
int mid=(l+r)>>1;
if (x<=mid) modify(k<<1,l,mid,x,y);
else modify(k<<1|1,mid+1,r,x,y);
push_up(k);
}
bool cmp2(frog x,frog y){
return x.id<y.id;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d%lld",&a[i].pos,&a[i].l),a[i].id=i;
std::sort(a+1,a+n+1,cmp);
build(1,1,n);
s.insert(mp(-1,0));
s.insert(mp(10000000000000000,0));
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&siz);
int id=query(1,1,n,x);
if (id==-1){
s.insert(mp(x,siz));
continue;
}
modify(1,1,n,id,siz);
ans[a[id].id]++;
a[id].l+=siz;
while (1){
it itt=s.upper_bound(mp(a[id].l+a[id].pos+1,-1));
itt--;
pli tt=*itt;
if (tt.fi==-1) break;
if (a[id].pos>tt.fi) break;
ans[a[id].id]++,a[id].l+=tt.se;
modify(1,1,n,id,tt.se);
s.erase(itt);
}
}
std::sort(a+1,a+n+1,cmp2);
for (int i=1;i<=n;i++) printf("%d %lld
",ans[i],a[i].l);
}
后记
因为蚊子的价值可能是 (0),然后第一次二分搜了一个 ((t+x+1,0)) 就挂了