参考题目来源、hzwer学长的题解链接
用lazy数组,简单
#include
using namespace std;
typedef long long ll;
#define maxn 50100
int n,l[maxn],r[maxn],belong[maxn],size,cnt;
ll v[maxn],a[maxn],lazy[maxn];
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
for(int i=1;i<=n;i++)
belong[i]=(i-1)/size+1;
}
void updata(int l_,int r_,ll val){
if(belong[l_]==belong[r_]){
for(int i=l_;i<=r_;i++)a[i]+=val;
return;
}
for(int i=l_;i<=r[belong[l_]];i++)a[i]+=val;
for(int i=belong[l_]+1;i<belong[r_];i++)lazy[i]+=val;
for(int i=l[belong[r_]];i<=r_;i++)a[i]+=val;
}
ll query(int x){
return a[x]+lazy[belong[x]];
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build();
int op,l,r,c;
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&op,&l,&r,&c);
if(op==0)updata(l,r,c);
else printf("%lld\n",query(r));
}
}
用lazy数组,非整体块暴力,整体块内排序+二分(vector)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=50007;
template<class T>inline void read(T &x){
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,size,cnt,l[N],r[N],belong[N];
int a[N],lazy[N];
vector<int>vec[505];
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/size+1;
vec[belong[i]].push_back(a[i]);
}
for(int i=1;i<=cnt;i++)
sort(vec[i].begin(),vec[i].end());
}
void reset(int x){
vec[x].clear();
for(int i=l[x];i<=r[x];i++)
vec[x].push_back(a[i]);
sort(vec[x].begin(),vec[x].end());
}
void add(int L,int R,int c){
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)a[i]+=c;
reset(belong[L]);
return;
}
for(int i=L;i<=r[belong[L]];i++)a[i]+=c;
reset(belong[L]);
for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
for(int i=l[belong[R]];i<=R;i++)a[i]+=c;
reset(belong[R]);
}
int query(int L,int R,int c){
int ans=0;
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)
if(a[i]+lazy[belong[i]]<c)ans++;
return ans;
}
for(int i=L;i<=r[belong[L]];i++)
if(a[i]+lazy[belong[i]]<c)ans++;
for(int i=belong[L]+1;i<belong[R];i++){
int x=c-lazy[i];
ans+=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
}
for(int i=l[belong[R]];i<=R;i++)
if(a[i]+lazy[belong[i]]<c)ans++;
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)read(a[i]);
build();
int opt,l,r,c;
for(int i=1;i<=n;i++){
read(opt);read(l);read(r);read(c);
if(opt==0)add(l,r,c);
else printf("%d\n",query(l,r,c*c));
}
}
用lazy数组,非整体块暴力,整体块内排序+二分(vector)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=100007;
template<class T>inline void read(T &x){
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,size,cnt,l[N],r[N],belong[N];
int a[N],lazy[N];
vector<int>vec[505];//块内排序
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/size+1;
vec[belong[i]].push_back(a[i]);
}
for(int i=1;i<=cnt;i++)
sort(vec[i].begin(),vec[i].end());
}
void reset(int x){//重新排序
vec[x].clear();
for(int i=l[x];i<=r[x];i++)
vec[x].push_back(a[i]);
sort(vec[x].begin(),vec[x].end());
}
void add(int L,int R,int c){
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)a[i]+=c;
reset(belong[L]);
return;
}
for(int i=L;i<=r[belong[L]];i++)a[i]+=c;
reset(belong[L]);
for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
for(int i=l[belong[R]];i<=R;i++)a[i]+=c;
reset(belong[R]);
}
int query(int L,int R,int c){
int pre=-1;
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)
if(a[i]+lazy[belong[i]]<c&&a[i]+lazy[belong[i]]>pre)pre=a[i]+lazy[belong[i]];
return pre;
}
for(int i=L;i<=r[belong[L]];i++)
if(a[i]+lazy[belong[i]]<c&&a[i]+lazy[belong[i]]>pre)pre=a[i]+lazy[belong[i]];
for(int i=belong[L]+1;i<belong[R];i++){
int x=c-lazy[i];
int p=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
if(p==0)continue;
if(vec[i][p-1]+lazy[i]>pre)pre=vec[i][p-1]+lazy[i];
}
for(int i=l[belong[R]];i<=R;i++)
if(a[i]+lazy[belong[i]]<c&&a[i]+lazy[belong[i]]>pre)pre=a[i]+lazy[belong[i]];
return pre;
}
int main(){
// freopen("a1.in","r",stdin);
cin>>n;
for(int i=1;i<=n;i++)read(a[i]);
build();
int opt,l,r,c;
for(int i=1;i<=n;i++){
read(opt);read(l);read(r);read(c);
if(opt==0)add(l,r,c);
else printf("%d\n",query(l,r,c));
}
// fclose(stdin);
}
lazy数组
#include
using namespace std;
typedef long long ll;
const int N=50007;
int n,m,size,cnt,l[N],r[N],belong[N];
ll v[N],a[N],lazy[N];
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++)belong[i]=(i-1)/size+1;
for(int i=1;i<=cnt;i++)
for(int j=l[i];j<=r[i];j++)
v[i]+=a[j];
}
inline void add(int L,int R,ll c){
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)a[i]+=c,v[belong[i]]+=c;
return;
}
for(int i=L;i<=r[belong[L]];i++)a[i]+=c,v[belong[i]]+=c;
for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
for(int i=l[belong[R]];i<=R;i++)a[i]+=c,v[belong[i]]+=c;
}
inline ll query(int L,int R,ll c){
ll ans=0;
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)ans=(ans+a[i]+lazy[belong[i]])%c;
return ans;
}
for(int i=L;i<=r[belong[L]];i++)ans=(ans+a[i]+lazy[belong[i]])%c;
for(int i=belong[L]+1;i<belong[R];i++)ans=(ans+v[i]+lazy[i]*(r[i]-l[i]+1))%c;
for(int i=l[belong[R]];i<=R;i++)ans=(ans+a[i]+lazy[belong[i]])%c;
return ans;
}
int main(){
//freopen("a1.in","r",stdin);
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
build();
int opt,l_,r_;ll c;
for(int i=1;i<=n;i++){
cin>>opt>>l_>>r_>>c;
if(opt==0)add(l_,r_,c);
else{
ll ans=query(l_,r_,c+1);
cout<<ans<<"\n";
}
}
//fclose(stdin);
}
int类型最多开方5次(向下取整)会变成1/0,就没有必要再开方了
非整体块暴力,整体块也暴力开方,用flag记录整体块内是否都已为1/0,(若是则直接累加,不需要再暴力块内元素了)
这样每个元素至多被开方不超过5次,显然复杂度没有问题。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x7fffffff
typedef long long ll;
const int N=50007;
int n,size,cnt,l[N],r[N],belong[N];
int a[N],v[N],flag[N];//flag判断块是否已为0/1
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++)belong[i]=(i-1)/size+1;
for(int i=1;i<=cnt;i++)
for(int j=l[i];j<=r[i];j++)
v[i]+=a[j];
}
void solve_sqrt(int x){//暴力对整体块开方
if(flag[x])return;
flag[x]=1;
v[x]=0;
for(int i=l[x];i<=r[x];i++){
a[i]=sqrt(a[i]);v[x]+=a[i];
if(a[i]>1)flag[x]=0;
}
}
void updata_sqrt(int L,int R){
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++){
v[belong[i]]-=a[i];
a[i]=sqrt(a[i]);
v[belong[i]]+=a[i];
}
return;
}
for(int i=L;i<=r[belong[L]];i++){
v[belong[i]]-=a[i];
a[i]=sqrt(a[i]);
v[belong[i]]+=a[i];
}
for(int i=belong[L]+1;i<belong[R];i++)
solve_sqrt(i);
for(int i=l[belong[R]];i<=R;i++){
v[belong[i]]-=a[i];
a[i]=sqrt(a[i]);
v[belong[i]]+=a[i];
}
}
int query(int L,int R){
int ans=0;
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)ans+=a[i];
return ans;
}
for(int i=L;i<=r[belong[L]];i++)ans+=a[i];
for(int i=belong[L]+1;i<belong[R];i++)ans+=v[i];
for(int i=l[belong[R]];i<=R;i++)ans+=a[i];
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build();
int opt,l_,r_,c;
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&opt,&l_,&r_,&c);
if(opt==0)updata_sqrt(l_,r_);
else printf("%d\n",query(l_,r_));
}
}
用vector的函数暴力插入,当某个块过大时重新分块(rebuild)
询问的时候找第k个元素在第几个块的哪个位置
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define Inf 0x7fffffff
typedef long long ll;
const int N=100007;
int size,cnt,belong[N],l[N],r[N];
int n,a[N],temp[N<<1];
vector<int>ve[1005];
template<class T>inline void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
pair<int,int>find(int k){//找第k个元素在第几个块内的哪个位置
int i=1;
while(k>ve[i].size())k-=ve[i].size(),i++;
return make_pair(i,k-1);
}
void rebuild(){//重新分块
int k=0;
for(int i=1;i<=cnt;i++){
for(vector<int>::iterator j=ve[i].begin();j!=ve[i].end();j++)
temp[++k]=*j; //*j是取迭代器内的元素
ve[i].clear();
}
int size2=sqrt(k),cnt2=(k-1)/size2+1;
for(int i=1;i<=k;i++)ve[(i-1)/size2+1].push_back(temp[i]);
cnt=(k-1)/size2+1;
}
void insert(int pos,int x){
pair<int,int>t=find(pos);
ve[t.first].insert(ve[t.first].begin()+t.second,x);
if(ve[t.first].size()>20*size)rebuild();
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)read(a[i]);
size=sqrt(n);cnt=(n-1)/size+1;
for(int i=1;i<=n;i++)ve[(i-1)/size+1].push_back(a[i]);
int opt,l_,r_,c;
for(int i=1;i<=n;i++){
read(opt);read(l_);read(r_);read(c);
if(opt==0)insert(l_,r_);
else{
pair<int,int>t=find(r_);
printf("%d\n",ve[t.first][t.second]);
}
}
}
lazy加法懒标记,lazy2乘法懒标记
让乘法标记的优先级高于加法(如果反过来的话,新的加法标记无法处理)
1.若当前的一个块乘以lazy2后加上lazy,这时进行一个乘c的操作,则原来的标记变成lazy2 *c,lazy *c
2.若当前的一个块乘以lazy2后加上lazy,这时进行一个加c的操作,则原来的标记变成lazy2, lazy +c
重点:每次更新非整体块时用reset下放标记
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x7fffffff
typedef long long ll;
const int N=100007,mod=10007;
int n,size,cnt,l[N],r[N],belong[N];
int a[N],lazy[N],lazy2[N];//lazy是加法标记,lazy2是乘法标记
template<class T>inline void read(T &x){
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++)belong[i]=(i-1)/size+1;
for(int i=1;i<=cnt;i++)lazy2[i]=1;
}
void reset(int x){
for(int i=l[x];i<=r[x];i++)
a[i]=(a[i]*lazy2[x]+lazy[x])%mod;
lazy[x]=0;lazy2[x]=1;
}
void add(int L,int R,int c){
if(belong[L]==belong[R]){
reset(belong[L]);
for(int i=L;i<=R;i++)a[i]=(a[i]+c)%mod;
return;
}
reset(belong[L]);
for(int i=L;i<=r[belong[L]];i++)a[i]=(a[i]+c)%mod;
for(int i=belong[L]+1;i<belong[R];i++)lazy[i]=(lazy[i]+c)%mod;
reset(belong[R]);
for(int i=l[belong[R]];i<=R;i++)a[i]=(a[i]+c)%mod;
}
void muti(int L,int R,int c){
if(belong[L]==belong[R]){
reset(belong[L]);
for(int i=L;i<=R;i++)a[i]=(a[i]*c)%mod;
return;
}
reset(belong[L]);
for(int i=L;i<=r[belong[L]];i++)a[i]=(a[i]*c)%mod;
for(int i=belong[L]+1;i<belong[R];i++){
lazy[i]=(lazy[i]*c)%mod;
lazy2[i]=(lazy2[i]*c)%mod;
}
reset(belong[R]);
for(int i=l[belong[R]];i<=R;i++)a[i]=(a[i]*c)%mod;
}
int query(int p){
return (a[p]*lazy2[belong[p]]+lazy[belong[p]])%mod;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)read(a[i]);
build();
int opt,l_,r_,c;
for(int i=1;i<=n;i++){
read(opt);read(l_);read(r_);read(c);
if(opt==0)add(l_,r_,c);else
if(opt==1)muti(l_,r_,c);else
printf("%d\n",query(r_));
}
}
非整体块暴力修改,整体块也暴力修改,用flag记录整体块是否修改为了同一元素,(若是则直接累加,不需要再暴力块内元素了)
重点:暴力非整体块时用reset下放整体块修改的值
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x7fffffff
typedef long long ll;
const int N=100007;
int n,size,cnt,l[N],r[N],belong[N];
int a[N],flag[N],v[N];
template<class T>void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++)
belong[i]=(i-1)/size+1;
}
void reset(int x){
if(!flag[x])return;
for(int i=l[x];i<=r[x];i++)a[i]=v[x];
flag[x]=0;
}
int query(int L,int R,int c){
int ans=0;
if(belong[L]==belong[R]){
reset(belong[L]);
for(int i=L;i<=R;i++)
if(a[i]==c)ans++;
else a[i]=c;
return ans;
}
reset(belong[L]);
for(int i=L;i<=r[belong[L]];i++)
if(a[i]==c)ans++;
else a[i]=c;
for(int i=belong[L]+1;i<belong[R];i++){
if(flag[i]){
if(v[i]==c)ans+=r[i]-l[i]+1;
else v[i]=c;
}else{
flag[i]=1;
for(int j=l[i];j<=r[i];j++){
if(a[j]==c)ans++;
else a[j]=c;
}
v[i]=c;
}
}
reset(belong[R]);
for(int i=l[belong[R]];i<=R;i++)
if(a[i]==c)ans++;
else a[i]=c;
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)read(a[i]);
build();
int l_,r_,c;
for(int i=1;i<=n;i++){
read(l_);read(r_);read(c);
printf("%d\n",query(l_,r_,c));
}
}
Ovo 这怎么查