CF609F Frogs and mosquitoes
阿新 • • 發佈:2020-09-15
題意
有 \(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)\) 就掛了