CF609F Frogs and mosquitoes

题意

(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)) 就挂了