題意
給定一個長度為 \(n\) 的陣列 \(a\),有 \(q\) 次操作。
-
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 L R x
,對於 \(L\le i\le R,a_i\ge 0\),讓 \(a_i+x\to a_i\)。 -
3 h
,讓 \(v_h+1\to v_h\)。 -
4 L R
,查詢有多少 \(L\le i\le R\) 滿足 \(a_i<0\)。 -
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;
}