1. 程式人生 > 實用技巧 >CF609F Frogs and mosquitoes

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\n",ans[i],a[i].l);
}

後記

因為蚊子的價值可能是 \(0\),然後第一次二分搜了一個 \((t+x+1,0)\) 就掛了