题意:
1.给出一个长为 的数列,以及 个操作,操作涉及区间加法,单点查值。
2.给出一个长为 的数列,以及 个操作,操作涉及区间加法,询问区间内小于某个值 的元素个数。
3.给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,询问区间内小于某个值 xx 的前驱(比其小的最大元素)。
4.给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,区间求和,mod(c+1)。
原题地址:
参考博客:https://www.cnblogs.com/Parsnip/p/10458689.html#
代码:
#include<bits/stdc++.h> #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define multiCase int T;cin>>T;for(int t=1;t<=T;t++) #define rep(i,a,b) for(int i=a;i<=b;i++) #define repp(i,a,b) for(int i=a;i<b;i++) #define per(i,a,b) for(int i=a;i>=b;i--) #define perr(i,a,b) for(int i=a;i>b;i--) #define pb push_back #define eb push_back #define mst(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; template <typename _Tp> inline _Tp read(_Tp&x){ char c11=getchar(),ob=0;x=0; while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1; while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x; } const int N=1000010,sqrtN=1000; int n,t,L[sqrtN],R[sqrtN],pos[N];//L[j]、R[j]分别表示第j个块所管辖区间的左边界和右边界,pos[i]表示序列中第i个元素属于哪个块 ll a[N],changed[sqrtN],sum[sqrtN];//a数组用来存序列元素,changed数组用来表示每个块中每个元素共同的变化量,sum数组用来存每个块中元素的和 vector<int>section[N];//用于管理每个块中的元素 //输入元素 inline void input() { scanf("%d",&n); rep(i,1,n)scanf("%d",&a[i]); } //将对应元素存入对应的块 inline void reset(int x) { section[x].clear(); rep(i,L[x],R[x])section[x].pb(a[i]); sort(section[x].begin(),section[x].end()); } //预处理,分为sqrt(n)或sqrt(n)+1个块 inline void init() { t=sqrt(n); rep(i,1,t) { L[i]=(i-1)*t+1; R[i]=i*t; } if(R[t]<n)t++,L[t]=R[t-1]+1,R[t]=n; rep(i,1,t) rep(j,L[i],R[i]) pos[j]=i,sum[i]+=a[j]; rep(i,1,t)reset(i); } //区间修改,这里是整体加data inline void change(int l,int r,ll data) { int p=pos[l],q=pos[r]; if(q==p) { rep(i,l,r)a[i]+=data; sum[p]+=(r-l+1)*data; reset(p); } else { rep(i,p+1,q-1)changed[i]+=data; rep(i,l,R[p])a[i]+=data; sum[p]+=(R[p]-l+1)*data; reset(p); rep(i,L[q],r)a[i]+=data; sum[q]+=(r-L[q]+1)*data; reset(q); } } //用于更新区间内小于某个值 x 的前驱 inline void updata(ll &ans2,ll val,ll limit) { if(val<limit&&val>ans2)ans2=val; } //查询a[x]的值 inline ll ask1(int x) { return a[x]+changed[pos[x]]; } //查询区间内小于某个值limit的元素个数 inline int ask2(int l,int r,ll limit) { int p=pos[l],q=pos[r],ans1=0; if(p==q) { rep(i,l,r) if(a[i]+changed[p]<limit)ans1++; } else { rep(i,p+1,q-1)ans1+=lower_bound(section[i].begin(),section[i].end(),limit-changed[i])-section[i].begin(); rep(i,l,R[p])if(a[i]+changed[p]<limit)ans1++; rep(i,L[q],r)if(a[i]+changed[q]<limit)ans1++; } return ans1; } //询问区间内小于某个值 x 的前驱(比其小的最大元素) inline ll ask3(int l,int r,ll limit) { int p=pos[l],q=pos[r]; ll ans2=-1; if(p==q) { rep(i,l,r) updata(ans2,a[i]+changed[p],limit); } else { rep(i,p+1,q-1) updata(ans2,section[i][lower_bound(section[i].begin(),section[i].end(),limit-changed[i])-section[i].begin()-1]+changed[i],limit); rep(i,l,R[p]) updata(ans2,a[i]+changed[pos[i]],limit); rep(i,L[q],r) updata(ans2,a[i]+changed[pos[i]],limit); } return ans2; } //区间求和取模 inline ll ask4(int l,int r,ll MOD) { int p=pos[l],q=pos[r]; ll ans3=0; if(p==q) { rep(i,l,r)ans3=(ans3+a[i])%MOD; ans3=(ans3+(r-l+1)*changed[p])%MOD; } else { rep(i,p+1,q-1)ans3=(ans3+sum[i]%MOD+(R[i]-L[i]+1)*changed[i])%MOD; rep(i,l,R[p])ans3=(ans3+a[i]+changed[pos[i]])%MOD; rep(i,L[q],r)ans3=(ans3+a[i]+changed[pos[i]])%MOD; } return ans3; } inline void solve() { input(); init(); int opt,l,r;ll c; rep(i,1,n) { scanf("%d%d%d%lld",&opt,&l,&r,&c); if(opt)printf("%lld ",ask4(l,r,c+1)); else change(l,r,c); } } int main() { solve(); return 0; }