【题解】「JOISC 2021 Day1」饮食区

solution:

考虑算法:整体二分

考虑没有删除怎么做。因为满足单调性,可以直接二分 使得队列人数第一次 ≥ B i \geq B_i Bi 时的修改编号

加上删除操作后还是有单调性,只不过要 预处理出删除操作对查询的影响

这里抛出一个结论:从左往右扫描,删除对当前询问影响=当前加入队列的总人数-当前实际人数。

考虑后面的,本质上就是每次全部元素对 0 取 max ,考虑 区间最值线段树

维护懒标 ( p , q ) (p,q) (p,q) 表示区间里的数 +p 后对 q 取 max ,合并结果大致为:

q = max ⁡ ( q + u , v ) q=\max (q+u,v) q=max(q+u,v)

p = p + u p=p+u p=p+u

合并标记时要注意先后顺序。

整个过程完全可以用 线段树+树状数组 维护。满足 区间修改 + 单点查询。

总结:本题考查一些数据结构常见算法。我都没见过。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int Maxn=3e5+5;
int n,m,Q,ans[Maxn],cnt,idx[Maxn],qidx,sidx;
ll bit[Maxn];
inline ll read()
{
	ll X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}
struct node{
	int type,l,r,id;
	ll k;
}q[Maxn],q1[Maxn],q2[Maxn];
struct SegmentTree{
	//(p,q) 表示区间里的数 +p 后对 q 取 max 
	//合并标记要注意先后顺序 
	struct node{
		ll p,q;
	}t[Maxn<<2];
	void PushUp(int p,ll u,ll v) {
		t[p].q=max(t[p].q+u,v);
		t[p].p+=u;
	}
	void PushDown(int p) {
		if(t[p].p||t[p].q) {
			PushUp(p<<1,t[p].p,t[p].q);
			PushUp(p<<1|1,t[p].p,t[p].q);
			t[p].p=t[p].q=0;
		}
	}
	void upd(int p,int l,int r,int ql,int qr,int k) {
		if(ql<=l&&r<=qr) {
			PushUp(p,k,0);
			return;
		}
		PushDown(p);
		int mid=l+r>>1;
		if(ql<=mid) upd(p<<1,l,mid,ql,qr,k);
		if(mid<qr) upd(p<<1|1,mid+1,r,ql,qr,k);
	}
	ll qry(int p,int l,int r,int x) {
		if(l==r) return max(t[p].p,t[p].q);
		int mid=l+r>>1; PushDown(p);
		return x<=mid?qry(p<<1,l,mid,x):qry(p<<1|1,mid+1,r,x); 
	}
}T1;
void add(int x,int k) {
	for(int i=x;i<=n;i+=i&-i) bit[i]+=k;
}
ll qry(int x) {
	ll tot=0;
	for(int i=x;i;i-=i&-i) tot+=bit[i];
	return tot;
}
void solve(int l,int r,int ql,int qr) {
	if(l>r||ql>qr) return;
	int mid=ql+qr>>1;
	int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
	for(int i=l;i<=r;i++) {
		//对于询问操作,判断是否到达 k 
		if(q[i].type==0) {
			ll tmp=qry(q[i].l);
			if(tmp>=q[i].k) {
				q1[++cnt1]=q[i];
				cnt3++;
			}
			else {
				q[i].k-=tmp;
				q2[++cnt2]=q[i];
				cnt4++;
			}
		}
		else {
			if(q[i].id<=mid) {
				add(q[i].l,q[i].k);
				add(q[i].r+1,-q[i].k);
				q1[++cnt1]=q[i];
			}
			else {
				q2[++cnt2]=q[i];
			}
		}
	}
	for(int i=l;i<=r;i++) {
		if(q[i].type==1&&q[i].id<=mid) {
			add(q[i].l,-q[i].k);
			add(q[i].r+1,q[i].k);
		}
	}
	if(ql==qr) {
		for(int i=1;i<=cnt1;i++) {
			if(q1[i].type==0) {
				ans[q1[i].id]=idx[ql];
			}
		}
		return;
	}
	for(int i=1;i<=cnt1;i++) {
		q[l+i-1]=q1[i];
	}
	for(int i=1;i<=cnt2;i++) {
		q[l+cnt1+i-1]=q2[i];
	}
	if(cnt3) solve(l,l+cnt1-1,ql,mid);
	if(cnt4) solve(l+cnt1,r,mid+1,qr);
}
signed main() {
//	freopen("data.in","r",stdin);
	n=read(),m=read(),Q=read();
	for(int i=1;i<=Q;i++) {
		int op=read();
		if(op==1) {
			int l=read(),r=read(),c=read(),k=read();
			q[++cnt].type=1;
			q[cnt].l=l;
			q[cnt].r=r;
			q[cnt].k=k;
			q[cnt].id=++qidx;
			idx[qidx]=c;
			add(l,k),add(r+1,-k);
			T1.upd(1,1,n,l,r,k);
		}
		else if(op==2) {
			int l=read(),r=read(),k=read();
			T1.upd(1,1,n,l,r,-k);
		}
		else if(op==3) {
			int l=read(); ll k=read();
			q[++cnt].type=0;
			q[cnt].l=l;
			q[cnt].k=k+qry(l)-T1.qry(1,1,n,l);
			q[cnt].id=++sidx;
		}
	}
	memset(bit,0,sizeof(bit));
	solve(1,cnt,1,qidx);
	for(int i=1;i<=sidx;i++) {
		printf("%lld\n",ans[i]);
	}
}
posted @ 2021-08-28 13:28  仰望星空的蚂蚁  阅读(34)  评论(0)    收藏  举报  来源