GYM350340K.King Kog's Reception(巧妙的線段樹)
阿新 • • 發佈:2021-10-23
維護一個佇列,每個人有抵達時間和操作時間。
要求維護以下三種操作:
1)t時刻來一個人,它操作需要d秒。
2)t時刻要來的那個人不來了。
3)如果t時刻去排隊,需要等多久才能輪到你。
做法:
巧妙的線段樹,以時間為下標建樹,每個節點維護兩個資訊:
1)這個區間內所有來的人的操作時間之和c。
2)完成這個區間內所有人的最早截至時間mx。
那麼有轉移方程:
1)c[i]=c[i<<1]+c[i<<1|1]
2)mx[i]=max(mx[i<<1]+c[i<<1|1],mx[i<<1|1])
正常單點修改+區間查詢。
有點線段樹上樹形DP的感覺。很牛,我確實想不到,一種船新的技巧。
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+10; int q; long long mx[maxn<<2],c[maxn<<2]; void build (int i,int l,int r) { if (l==r) { mx[i]=l; return; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); c[i]=c[i<<1]+c[i<<1|1]; mx[i]=max(mx[i<<1]+c[i<<1|1],mx[i<<1|1]); } void up (int i,int l,int r,int p,int v) { if (l==r) { c[i]+=v; mx[i]+=v; return; } int mid=(l+r)>>1; if (p<=mid) up(i<<1,l,mid,p,v); if (p>mid) up(i<<1|1,mid+1,r,p,v); c[i]=c[i<<1]+c[i<<1|1]; mx[i]=max(mx[i<<1]+c[i<<1|1],mx[i<<1|1]); } pair<long long,long long> query (int i,int l,int r,int L,int R) { if (l>=L&&r<=R) return {c[i],mx[i]}; pair<long long,long long> ans={0,0}; int mid=(l+r)>>1; if (L<=mid) { pair<long long,long long> tt=query(i<<1,l,mid,L,R); ans.first=ans.first+tt.first; ans.second=max(ans.second+tt.first,tt.second); } if (R>mid) { pair<long long,long long> tt=query(i<<1|1,mid+1,r,L,R); ans.first=ans.first+tt.first; ans.second=max(ans.second+tt.first,tt.second); } return ans; } pair<int,int> qq[maxn]; int main () { cin>>q; int mm=1e6; build(1,1,mm); for (int i=1;i<=q;i++) { //getchar(); char op; int t,d; cin>>op; if (op=='?') { int x; cin>>x; printf("%lld\n",query(1,1,mm,1,x).second-x); } else if (op=='+') { int t,d; cin>>t>>d; qq[i]={t,d}; up(1,1,mm,t,d); } else { int p; cin>>p; up(1,1,mm,qq[p].first,-qq[p].second); } } }