2024.10.17 模拟赛T3 题解

aeiouaoeiu / 2024-10-22 / 原文

题意

给定一个长度为 \(n\) 的数组 \(a\),有 \(q\) 次操作。

  1. 1 L R x,对于 \(L\le i\le R\),若 \(v_i>0\) 则让 \(v_i-1\to v_i\),否则让 \(a_i-x\to a_i\)

  2. 2 L R x,对于 \(L\le i\le R,a_i\ge 0\),让 \(a_i+x\to a_i\)

  3. 3 h,让 \(v_h+1\to v_h\)

  4. 4 L R,查询有多少 \(L\le i\le R\) 满足 \(a_i<0\)

  5. 5 L R,查询有多少 \(L\le i\le R\) 满足 \(a_i=0\)

\(1\le n,m\le 2\times 10^5\)

解法

开一个线段树,维护区间内有多少 \(a_i<0\),非负的最小值,非负的最小值个数三种信息。

显然可以暴力处理操作一后 \(a_i<0\) 的情况。

对于 \(v\),可以直接开 set 在操作一前找到 \(v_i>0\) 的那些,直接给那些数加上 \(x\)

这样就写完了。

#include<bits/stdc++.h>
#define pb emplace_back
#define pob pop_back
#define mp make_pair
using namespace std;
typedef long long ll;
typedef __int128 LL;
const ll maxn=200007,ee=1e18,p=998244353;
ll n,q,a[maxn],vis[maxn];
set<pair<ll,ll> > st;
vector<ll> del;
struct Node{
	ll mn,cnt;
	Node operator+(Node o){
		Node res;
		if(mn==-1) res.mn=o.mn,res.cnt=o.cnt;
		else if(o.mn==-1) res.mn=mn,res.cnt=cnt;
		else if(mn==o.mn) res.mn=mn,res.cnt=cnt+o.cnt;
		else if(mn<o.mn) res.mn=mn,res.cnt=cnt;
		else res.mn=o.mn,res.cnt=o.cnt;
		return res;
	}
};
struct Tree{
	Node t[maxn<<2];
	ll val[maxn<<2],add[maxn<<2];
	void pushup(ll rt){
		val[rt]=val[rt<<1]+val[rt<<1|1];
		t[rt]=t[rt<<1]+t[rt<<1|1];
	}
	void pushdown(ll rt){
		if(!add[rt]) return;
		if(t[rt<<1].mn!=-1) t[rt<<1].mn+=add[rt];
		if(t[rt<<1|1].mn!=-1) t[rt<<1|1].mn+=add[rt];
		add[rt<<1]+=add[rt],add[rt<<1|1]+=add[rt],add[rt]=0;
	}
	void upd1(ll l,ll r,ll x,ll y,ll z,ll rt){
		if(x<=l&&r<=y){
			//cout<<l<<" "<<r<<" "<<t[rt].mn<<"\n";
			if(t[rt].mn==-1) return;
			if(l==r&&t[rt].mn<z) return val[rt]=1,t[rt]=Node{-1,0},void();
			if(t[rt].mn>=z) return t[rt].mn-=z,add[rt]-=z,void();
			if(l!=r) pushdown(rt); ll mid=(l+r)>>1;
			upd1(l,mid,x,y,z,rt<<1),upd1(mid+1,r,x,y,z,rt<<1|1);
			pushup(rt); return;
		}
		pushdown(rt); ll mid=(l+r)>>1;
		if(x<=mid) upd1(l,mid,x,y,z,rt<<1); if(mid<y) upd1(mid+1,r,x,y,z,rt<<1|1);
		pushup(rt);
	}
	void upd2(ll l,ll r,ll x,ll y,ll z,ll rt){
		if(x<=l&&r<=y) return add[rt]+=z,t[rt].mn+=z,void(); pushdown(rt); ll mid=(l+r)>>1;
		if(x<=mid) upd2(l,mid,x,y,z,rt<<1); if(mid<y) upd2(mid+1,r,x,y,z,rt<<1|1);
		pushup(rt);
	}
	void build(ll l,ll r,ll rt){
		if(l==r) return cin>>t[rt].mn,t[rt].cnt=1,void(); ll mid=(l+r)>>1;
		build(l,mid,rt<<1),build(mid+1,r,rt<<1|1),pushup(rt);
	}
	ll qry1(ll l,ll r,ll x,ll y,ll rt){
		if(x<=l&&r<=y) return val[rt]; pushdown(rt); ll mid=(l+r)>>1,res=0;
		if(x<=mid) res+=qry1(l,mid,x,y,rt<<1); if(mid<y) res+=qry1(mid+1,r,x,y,rt<<1|1);
		return res;
	}
	Node qry2(ll l,ll r,ll x,ll y,ll rt){
		if(l>r||r<x||y<l) return Node{-1,0};
		if(x<=l&&r<=y) return t[rt]; pushdown(rt); ll mid=(l+r)>>1;
		return qry2(l,mid,x,y,rt<<1)+qry2(mid+1,r,x,y,rt<<1|1);
	}
}tree;
int main(void){
	freopen("simulator.in","r",stdin);
	freopen("simulator.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n; tree.build(1,n,1);
	cin>>q;
	for(ll i=1,opt,x,y,z,tmp;i<=q;i++){
		cin>>opt>>x;
		if(opt==1){
			cin>>y>>z;
			auto it=st.lower_bound(mp(x,0));
			del.clear();
			for(;it!=st.end()&&it->first<=y;it++){
				tmp=it->first;
				tree.upd2(1,n,tmp,tmp,z,1);
				del.pb(tmp);
			}
			for(auto t:del){
				auto pir=*st.lower_bound(mp(t,0));
				st.erase(pir),vis[t]--;
				if(pir.second>1) pir.second--,st.insert(pir);
			}
			tree.upd1(1,n,x,y,z,1);
		}else if(opt==2){
			cin>>y>>z;
			tree.upd2(1,n,x,y,z,1);
		}else if(opt==3){
			if(vis[x]){
				auto pir=*st.find(mp(x,vis[x]));
				st.erase(pir); pir.second++;
				st.insert(pir);
			}else st.insert(mp(x,1));
			vis[x]++;
		}else if(opt==4){
			cin>>y;
			cout<<tree.qry1(1,n,x,y,1)<<"\n";
		}else{
			cin>>y;
			Node res=tree.qry2(1,n,x,y,1);
			if(res.mn==0) cout<<res.cnt<<"\n";
			else cout<<"0\n";
		}
	}
	return 0;
}