「JOISC 2021 Day1」飲食區
阿新 • • 發佈:2021-07-01
考慮將所有所有修改和詢問離線下來,並且將佇列編號看成時刻。這樣就可以將操作一二的修改拆開,變成在\(L_i\)時刻加入資料結構,在\(R_i+1\)時刻彈出資料結構。
考慮使用一棵普通的線段樹維護,下標為操作的順序(因為操作也是有順序的),每個節點維護當前區間元素的個數(可以是負數),區間最大元素子段和,區間加入元素的個數。
然後修改就單點修改,查詢的時候線段樹上二分即可。
int n,m,q; int opt[255555],L[255555],R[255555],C[255555],K[255555]; struct seg { int v,l,s; inline seg(int V=0,int L=0,int S=0): v(V),l(L),s(S) {} inline void upd(const seg &A){v+=A.v;l=max(l+A.v,A.l);s+=A.s;} }t[1111111]; int ans[255555]; vector<pair<seg,int>>md[255555]; vector<pii>qu[255555]; inline seg upd(const seg &A,const seg &B) { return seg(A.v+B.v,max(A.l+B.v,B.l),A.s+B.s); } inline void push_up(int x) { t[x]=upd(t[x<<1],t[x<<1|1]); } void modify(int p,int l,int r,int x,const seg &k) { if(l==r) {t[x]=k;return;} int mid=(l+r)>>1; if(p<=mid) modify(p,l,mid,x<<1,k); else modify(p,mid+1,r,x<<1|1,k); push_up(x); } void query(int p,int l,int r,int x,seg &sum) { if(l==r) { sum.upd(t[x]); return; } int mid=(l+r)>>1; if(p<=mid) query(p,l,mid,x<<1,sum); else sum.upd(t[x<<1]),query(p,mid+1,r,x<<1|1,sum); } int query_k(int l,int r,int x,int k) { if(l==r) return l; int mid=(l+r)>>1; if(t[x<<1].s>=k) return query_k(l,mid,x<<1,k); else return query_k(mid+1,r,x<<1|1,k-t[x<<1].s); } signed main() { ios::sync_with_stdio(0); cin.tie(0); cin>>n>>m>>q; R(i,1,q) { cin>>opt[i]; if(opt[i]==1) { cin>>L[i]>>R[i]>>C[i]>>K[i]; md[L[i]].pb(mkp(seg(K[i],K[i],K[i]),i)); md[R[i]+1].pb(mkp(seg(0,0,0),i)); } if(opt[i]==2) { cin>>L[i]>>R[i]>>K[i]; md[L[i]].pb(mkp(seg(-K[i],0,0),i)); md[R[i]+1].pb(mkp(seg(0,0,0),i)); } if(opt[i]==3) { cin>>L[i]>>R[i]; qu[L[i]].pb(mkp(R[i],i)); } } R(t,1,n) { for(const auto &qwq:md[t]) modify(qwq.se,1,q,1,qwq.fi); for(const auto &qwq:qu[t]) { seg sum; query(qwq.se,1,q,1,sum); //printf("v:%lld l:%lld\n",sum.v,sum.l); ckmax(sum.v,sum.l); if(sum.v>=qwq.fi) { int k=sum.s-sum.v+qwq.fi; //printf("s:%lld v:%lld\n",sum.s,sum.v); ans[qwq.se]=C[query_k(1,q,1,k)]; } } } R(i,1,q) if(opt[i]==3) cout<<ans[i]<<'\n'; }