AT_joisc2021_c フードコート (Foodcourt)

古早题解写的太丑了,改一下。

换维扫描线好题。

发现删除操作会出现过删(即删除的个数大于序列中元素数),这个很难处理。

思考一下应该能想到将每次询问查询的 \(b\to cnt_{del}+b\) 其中 \(cnt_{del}\) 为在该询问之前这个序列删除的数的个数,这样就不用删除只需插入即可。但是这样对于每个删除操作操作的每个序列都要求出删了多少个数,很困难,时间复杂度不能接受。

对于一个询问 \((A,B)\) 发现如果能找到序列 \(A\) 在此询问之前操作序列中最后一次出现过删的操作,对于该位置后的操作序列对 \(B\) 的贡献就可以用上文的方法求,而该操作及之前加入的所有元素都已经清空,只需将 \(b\to b+cnt_{add}\) 即可,这里的 \(cnt_{add}\) 表示该操作前加入的元素个数和。

以店铺维做扫描线,以操作序列建立线段树,叶子节点 \([i,i]\) 上维护第 \(1\) 到第 \(i\) 次操作的过程中共加的元素总数(不计删除)记为 \(add_i\) 以及经过 \(1\)\(i\) 操作加的元素总数减去删除的元素总数记为 \(sum_i\)(不考虑过删),节点 \([l,r]\) 维护 \(\max_{i=l}^{r}add_i,\min_{i=l}^{r}sum_i\)

\(x\) 次操作,找到最后一个过删的位置即最后 \(\min_{i=1}^x sum\) 的位置 \(p\),显然之后的变化量均 \(>0\)。最后过删操作前加入的数均已删除,则只需要求出之后又删了几个数。

\(b\to b+add([1,x])-(sum([1,x])-sum([1,p]))\) 即可,根据定义容易得出 \(\sum add-\sum sum=\sum del\)

时间复杂度 \(O(n\log n)\)

// Problem: フードコート (Foodcourt)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_joisc2021_c
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mp make_pair
const int N=3e5+5;int num[N],ans[N];
struct oper{int opt,id,k,c;};vector<oper>g[N],a[N];
struct node{int l,r,add,sum,la,ls;}tr[N<<2];
void pushup(int u){tr[u].add=max(tr[u<<1].add,tr[u<<1|1].add),tr[u].sum=min(tr[u<<1].sum,tr[u<<1|1].sum);}
void pd(int u){
	if(tr[u].ls)tr[u<<1].ls+=tr[u].ls,tr[u<<1|1].ls+=tr[u].ls,tr[u<<1].sum+=tr[u].ls,tr[u<<1|1].sum+=tr[u].ls,tr[u].ls=0;
	if(tr[u].la)tr[u<<1].la+=tr[u].la,tr[u<<1|1].la+=tr[u].la,tr[u<<1].add+=tr[u].la,tr[u<<1|1].add+=tr[u].la,tr[u].la=0;
}
void build(int u,int l,int r){tr[u]={l,r};if(l==r)return;int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r);}
void add(int u,int l,int r,int d){if(tr[u].l>=l&&tr[u].r<=r)return tr[u].add+=d,tr[u].la+=d,void();
	pd(u);int mid=tr[u].l+tr[u].r>>1;if(l<=mid)add(u<<1,l,r,d);if(r>mid)add(u<<1|1,l,r,d);pushup(u);
}
void adds(int u,int l,int r,int d){if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum+=d,tr[u].ls+=d,void();
	pd(u);int mid=tr[u].l+tr[u].r>>1;if(l<=mid)adds(u<<1,l,r,d);if(r>mid)adds(u<<1|1,l,r,d);pushup(u);
}
int gtad(int u,int x){if(tr[u].l==tr[u].r)return tr[u].add;
	pd(u);int mid=tr[u].l+tr[u].r>>1;return (x<=mid?gtad(u<<1,x):gtad(u<<1|1,x));
}
int gtsum(int u,int l,int r){if(!l&&!r)return 0;if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum;
	pd(u);int mid=tr[u].l+tr[u].r>>1,mn=1e16;if(l<=mid)mn=min(mn,gtsum(u<<1,l,r));if(r>mid)mn=min(mn,gtsum(u<<1|1,l,r));return mn;
}
int askad(int u,int l,int r,int d){
	if(tr[u].add<d||tr[u].l>r||tr[u].r<l)return 0;if(tr[u].l==tr[u].r)return tr[u].l;
	pd(u);int w=askad(u<<1,l,r,d);return (w?w:askad(u<<1|1,l,r,d));
}
int asksum(int u,int l,int r,int d){
	if(tr[u].sum>d||tr[u].l>r||tr[u].r<l)return 0;if(tr[u].l==tr[u].r)return tr[u].l;
	pd(u);int w=asksum(u<<1|1,l,r,d);return (w?w:asksum(u<<1,l,r,d));
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n,m,q,c0=0,c1=0;cin>>n>>m>>q;
	for(int i=1,opt,l,r,c,k;i<=q;i++){cin>>opt>>l>>r;
		if(opt==1)cin>>num[++c0]>>k,g[l].push_back(oper{1,c0,k}),g[r+1].push_back(oper{1,c0,-k});
		else if(opt==2)++c0,cin>>k,g[l].push_back(oper{2,c0,-k}),g[r+1].push_back(oper{2,c0,k});
		else a[l].push_back(oper{3,++c1,c0,r});
	}build(1,1,c0);
	for(int i=1;i<=n;i++){
		for(oper j:g[i]){
			if(j.opt==1)add(1,j.id,c0,j.k);
			adds(1,j.id,c0,j.k);
		}
		for(oper j:a[i]){int mn=gtsum(1,1,j.k);
			int beg=(mn<0?asksum(1,1,j.k,mn):0);
			ans[j.id]=num[askad(1,beg+1,j.k,gtad(1,j.k)-gtsum(1,j.k,j.k)+gtsum(1,beg,beg)+j.c)];
		}
	}
	for(int i=1;i<=c1;i++)cout<<ans[i]<<endl;
	return 0;
}
posted @ 2025-10-16 16:42  Uesugi1  阅读(7)  评论(0)    收藏  举报