2024.10.17 模擬賽T3 題解

aeiouaoeiu發表於2024-10-17

題意

給定一個長度為 \(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;
}