目錄
1.區間加法、單點查值
用lazy數組,簡單
#include<bits/stdc++.h>
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));
}
}
2.區間加法、詢問區間內小於變量c的元素個數
用lazy數組,非整體塊暴力,整體塊內排序+二分(vector)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<set>
#include<algorithm>
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));
}
}
3.區間加法、詢問區間內小於變量c的前驅(比其小的最大元素)
用lazy數組,非整體塊暴力,整體塊內排序+二分(vector)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<set>
#include<algorithm>
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);
}
4.區間加法,區間求和
lazy數組
#include<bits/stdc++.h>
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);
}
5.區間開方、區間求和
int類型最多開方5次(向下取整)會變成1/0,就沒有必要再開方了
非整體塊暴力,整體塊也暴力開方,用flag記錄整體塊內是否都已爲1/0,(若是則直接累加,不需要再暴力塊內元素了)
這樣每個元素至多被開方不超過5次,顯然複雜度沒有問題。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
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_));
}
}
6.單點插入,單點詢問
用vector的函數暴力插入,當某個塊過大時重新分塊(rebuild)
詢問的時候找第k個元素在第幾個塊的哪個位置
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<vector>
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]);
}
}
}
7.區間加法、區間乘法、單點查值
lazy加法懶標記,lazy2乘法懶標記
讓乘法標記的優先級高於加法(如果反過來的話,新的加法標記無法處理)
1.若當前的一個塊乘以lazy2後加上lazy,這時進行一個乘c的操作,則原來的標記變成lazy2 *c,lazy *c
2.若當前的一個塊乘以lazy2後加上lazy,這時進行一個加c的操作,則原來的標記變成lazy2, lazy +c
重點:每次更新非整體塊時用reset下放標記
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
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_));
}
}
8.區間詢問等於一個數c的元素,並將這個區間的所有元素改爲c
非整體塊暴力修改,整體塊也暴力修改,用flag記錄整體塊是否修改爲了同一元素,(若是則直接累加,不需要再暴力塊內元素了)
重點:暴力非整體塊時用reset下放整體塊修改的值
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
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));
}
}
9.詢問區間最小衆數
Ovo 這怎麼查