目录
1.区间加+单点查
每个块维护tag,散的暴力改。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=50010; const int maxt=250; int n,t,cnt; int a[maxn],tag[maxt],L[maxt],R[maxt],pos[maxn]; inline void add(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)a[i]+=k; return; } for(int i=ql;i<=R[pos[ql]];i++)a[i]+=k; for(int i=L[pos[qr]];i<=qr;i++)a[i]+=k; if(pos[ql]+1<=pos[qr]-1)for(int i=pos[ql]+1;i<=pos[qr]-1;i++)tag[i]+=k; } int main() { scanf("%d",&n); t=sqrt(n);cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++) { int op,x,y,k; scanf("%d%d%d%d",&op,&x,&y,&k); if(!op)add(x,y,k); else printf("%d\n",a[y]+tag[pos[y]]); } return 0; }
2.区间加+查询区间小于某个数的数的个数
与这题类似。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=50010; const int maxt=250; int n,t,cnt; int a[maxn],b[maxn],L[maxt],R[maxt],pos[maxn],tag[maxt]; inline void add(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)a[i]+=k; for(int i=L[pos[ql]];i<=R[pos[qr]];i++)b[i]=a[i]; sort(b+L[pos[ql]],b+R[pos[qr]]+1); return; } for(int i=ql;i<=R[pos[ql]];i++)a[i]+=k; for(int i=L[pos[ql]];i<=R[pos[ql]];i++)b[i]=a[i]; sort(b+L[pos[ql]],b+R[pos[ql]]+1); for(int i=L[pos[qr]];i<=qr;i++)a[i]+=k; for(int i=L[pos[qr]];i<=R[pos[qr]];i++)b[i]=a[i]; sort(b+L[pos[qr]],b+R[pos[qr]]+1); if(pos[ql]+1<=pos[qr]-1)for(int i=pos[ql]+1;i<=pos[qr]-1;i++)tag[i]+=k; } inline int query(int ql,int qr,int k) { int res=0; if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)if(a[i]+tag[pos[ql]]<k)res++; return res; } for(int i=ql;i<=R[pos[ql]];i++)if(a[i]+tag[pos[ql]]<k)res++; for(int i=L[pos[qr]];i<=qr;i++)if(a[i]+tag[pos[qr]]<k)res++; if(pos[ql]+1<=pos[qr]-1) for(int i=pos[ql]+1;i<=pos[qr]-1;i++) { int l=L[i],r=R[i],ans=0; while(l<=r) { int mid=(l+r)>>1; if(b[mid]+tag[i]<k)l=mid+1,ans=mid-L[i]+1; else r=mid-1; } res+=ans; } return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i]; t=sqrt(n);cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=cnt;i++)sort(b+L[i],b+R[i]+1); for(int i=1;i<=n;i++) { int op,l,r,k;scanf("%d%d%d%d",&op,&l,&r,&k); if(!op)add(l,r,k); else printf("%d\n",query(l,r,k*k)); } return 0; }
3.区间加+区间查前驱
每个块内放个multiset,查询时lower_bound
code:
#include<bits/stdc++.h> using namespace std; const int maxn=100010; const int maxt=350; int n,t,cnt; int a[maxn],L[maxt],R[maxt],pos[maxn],tag[maxt]; multiset<int>s[maxt]; inline void add(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)s[pos[ql]].erase(s[pos[ql]].find(a[i])); for(int i=ql;i<=qr;i++)a[i]+=k; for(int i=ql;i<=qr;i++)s[pos[ql]].insert(a[i]); return; } for(int i=ql;i<=R[pos[ql]];i++)s[pos[ql]].erase(s[pos[ql]].find(a[i])); for(int i=ql;i<=R[pos[ql]];i++)a[i]+=k; for(int i=ql;i<=R[pos[ql]];i++)s[pos[ql]].insert(a[i]); for(int i=L[pos[qr]];i<=qr;i++)s[pos[qr]].erase(s[pos[qr]].find(a[i])); for(int i=L[pos[qr]];i<=qr;i++)a[i]+=k; for(int i=L[pos[qr]];i<=qr;i++)s[pos[qr]].insert(a[i]); if(pos[ql]+1<=pos[qr]-1)for(int i=pos[ql]+1;i<=pos[qr]-1;i++)tag[i]+=k; } inline int query(int ql,int qr,int k) { int res=-1; if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)if(a[i]+tag[pos[ql]]<k)res=max(res,a[i]+tag[pos[ql]]); return res; } for(int i=ql;i<=R[pos[ql]];i++)if(a[i]+tag[pos[ql]]<k)res=max(res,a[i]+tag[pos[ql]]); for(int i=L[pos[qr]];i<=qr;i++)if(a[i]+tag[pos[qr]]<k)res=max(res,a[i]+tag[pos[qr]]); if(pos[ql]+1<=pos[qr]-1) for(int i=pos[ql]+1;i<=pos[qr]-1;i++) { set<int>::iterator it=s[i].lower_bound(k-tag[i]); if(it==s[i].begin())continue; it--; res=max(res,*it+tag[i]); } return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); t=sqrt(n),cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=n;i++)s[pos[i]].insert(a[i]); for(int i=1;i<=n;i++) { int op,l,r,k;scanf("%d%d%d%d",&op,&l,&r,&k); if(!op)add(l,r,k); else printf("%d\n",query(l,r,k)); } return 0; }
4.区间加+区间和
类似线段树对块打标记。
code:
#include<bits/stdc++.h> using namespace std; #define int long long const int maxn=50010; const int maxt=250; int n,t,cnt; int a[maxn],L[maxt],R[maxt],pos[maxn],sum[maxt],tag[maxt]; inline void add(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)a[i]+=k; sum[pos[ql]]+=(qr-ql+1)*k; return; } for(int i=ql;i<=R[pos[ql]];i++)a[i]+=k; sum[pos[ql]]+=(R[pos[ql]]-ql+1)*k; for(int i=L[pos[qr]];i<=qr;i++)a[i]+=k; sum[pos[qr]]+=(qr-L[pos[qr]]+1)*k; if(pos[ql]+1<=pos[qr]-1)for(int i=pos[ql]+1;i<=pos[qr]-1;i++)tag[i]+=k; } inline int query(int ql,int qr,int mod) { int res=0; if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)res=(res+(a[i]+tag[pos[ql]])%mod)%mod; return res; } for(int i=ql;i<=R[pos[ql]];i++)res=(res+(a[i]+tag[pos[ql]])%mod)%mod; for(int i=L[pos[qr]];i<=qr;i++)res=(res+(a[i]+tag[pos[qr]])%mod)%mod; if(pos[ql]+1<=pos[qr]-1) for(int i=pos[ql]+1;i<=pos[qr]-1;i++)res=(res+(sum[i]+(R[i]-L[i]+1)*tag[i]%mod)%mod)%mod; return res; } signed main() { scanf("%lld",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); t=sqrt(n),cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=n;i++)sum[pos[i]]+=a[i]; for(int i=1;i<=n;i++) { int op,l,r,k;scanf("%lld%lld%lld%lld",&op,&l,&r,&k); if(!op)add(l,r,k); else printf("%lld\n",query(l,r,k+1)); } return 0; }
5.区间开根+区间和
记录最大值,发现最大值小于等于1就不修改。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=50010; const int maxt=250; int n,t,cnt; int a[maxn],L[maxt],R[maxt],pos[maxn],sum[maxt],maxx[maxt]; inline void change(int ql,int qr) { if(pos[ql]==pos[qr]) { if(maxx[pos[ql]]<=1)return; for(int i=ql;i<=qr;i++)sum[pos[ql]]-=a[i],a[i]=sqrt(a[i]),sum[pos[ql]]+=a[i]; maxx[pos[ql]]=0; for(int i=L[pos[ql]];i<=R[pos[ql]];i++)maxx[pos[ql]]=max(maxx[pos[ql]],a[i]); return; } if(maxx[pos[ql]]>1)for(int i=ql;i<=R[pos[ql]];i++)sum[pos[ql]]-=a[i],a[i]=sqrt(a[i]),sum[pos[ql]]+=a[i]; if(maxx[pos[qr]]>1)for(int i=L[pos[qr]];i<=qr;i++)sum[pos[qr]]-=a[i],a[i]=sqrt(a[i]),sum[pos[qr]]+=a[i]; if(pos[ql]+1>pos[qr]-1)return; for(int i=pos[ql]+1;i<=pos[qr]-1;i++) { if(maxx[i]<=1)continue; sum[i]=maxx[i]=0; for(int j=L[i];j<=R[i];j++)a[j]=sqrt(a[j]),sum[i]+=a[j]; for(int j=L[i];j<=R[i];j++)maxx[i]=max(maxx[i],a[j]); } } inline int query(int ql,int qr) { int res=0; if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++)res+=a[i]; return res; } for(int i=ql;i<=R[pos[ql]];i++)res+=a[i]; for(int i=L[pos[qr]];i<=qr;i++)res+=a[i]; if(pos[ql]+1<=pos[qr]-1) for(int i=pos[ql]+1;i<=pos[qr]-1;i++)res+=sum[i]; return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); t=sqrt(n),cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=n;i++)sum[pos[i]]+=a[i],maxx[pos[i]]=max(maxx[pos[i]],a[i]); for(int i=1;i<=n;i++) { int op,l,r,k;scanf("%d%d%d%d",&op,&l,&r,&k); if(!op)change(l,r); else printf("%d\n",query(l,r)); } return 0; }
6.插入一个数+查第k个数
插入次数达到块长就重构,查询暴力跳。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=200010; const int maxt=500; int n,t,cnt,tot,num; int a[maxn],c[maxn]; vector<int>ve[maxt]; inline void rebuild() { num=tot=0; for(int i=1;i<=cnt;i++) { for(unsigned int j=0;j<ve[i].size();j++)a[++tot]=ve[i][j]; ve[i].clear(); } t=sqrt(tot);cnt=tot/t; if(tot%t)cnt++; for(int i=1;i<=tot;i++)ve[(i-1)/t+1].push_back(a[i]); } inline int find(int x) { int now=1; while(x>ve[now].size())x-=ve[now].size(),now++; return ve[now][x-1]; } inline void insert(int x,int k) { num++; int now=1; while(x>ve[now].size())x-=ve[now].size(),now++; ve[now].insert(ve[now].begin()+x-1,k); if(num==t)rebuild(); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); t=sqrt(n);cnt=n/t; if(n%t)cnt++; for(int i=1;i<=n;i++)ve[(i-1)/t+1].push_back(a[i]); for(int i=1;i<=n;i++) { int op,l,r,k;scanf("%d%d%d%d",&op,&l,&r,&k); if(!op)insert(l,r); else printf("%d\n",find(r)); } return 0; }
7.区间乘+区间加+单点查
像线段树2那样维护标记即可
code:
#include<bits/stdc++.h> using namespace std; const int maxn=100010; const int maxt=350; const int mod=10007; int n,t,cnt; int a[maxn],pos[maxn],L[maxt],R[maxt],tag1[maxt],tag2[maxt]; inline void down(int x) { for(int i=L[x];i<=R[x];i++)a[i]=(a[i]*tag2[x]%mod+tag1[x])%mod; tag1[x]=0,tag2[x]=1; } inline void add(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { down(pos[ql]); for(int i=ql;i<=qr;i++)a[i]=(a[i]+k)%mod; return; } down(pos[ql]); for(int i=ql;i<=R[pos[ql]];i++)a[i]=(a[i]+k)%mod; down(pos[qr]); for(int i=L[pos[qr]];i<=qr;i++)a[i]=(a[i]+k)%mod; if(pos[ql]+1<=pos[qr]-1)for(int i=pos[ql]+1;i<=pos[qr]-1;i++)tag1[i]=(tag1[i]+k)%mod; } inline void mul(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { down(pos[ql]); for(int i=ql;i<=qr;i++)a[i]=a[i]*k%mod; return; } down(pos[ql]); for(int i=ql;i<=R[pos[ql]];i++)a[i]=a[i]*k%mod; down(pos[qr]); for(int i=L[pos[qr]];i<=qr;i++)a[i]=a[i]*k%mod; if(pos[ql]+1<=pos[qr]-1) for(int i=pos[ql]+1;i<=pos[qr]-1;i++) tag1[i]=tag1[i]*k%mod,tag2[i]=tag2[i]*k%mod; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); t=sqrt(n),cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=cnt;i++)tag2[i]=1; for(int i=1;i<=n;i++) { int op,l,r,k;scanf("%d%d%d%d",&op,&l,&r,&k); if(!op)add(l,r,k); if(op==1)mul(l,r,k); if(op==2)printf("%d\n",(a[r]*tag2[pos[r]]%mod+tag1[pos[r]])%mod); } return 0; }
8.每次查询一个区间等于某个值的数的个数并将区间赋值为这个值
显然有势能,维护每个块是否被覆盖和覆盖的颜色,每次重构两个散块
code:
#include<bits/stdc++.h> using namespace std; const int maxn=100010; const int maxt=350; int n,t,cnt; int a[maxn],pos[maxn],L[maxt],R[maxt],col[maxt]; inline void down(int x) { if(col[x]==-1)return; for(int i=L[x];i<=R[x];i++)a[i]=col[x]; } inline void reset(int x,int k) { col[x]=k; for(int i=L[x];i<=R[x];i++)if(a[i]!=k)col[x]=-1; } inline int query(int ql,int qr,int k) { int res=0; if(pos[ql]==pos[qr]) { if(~col[pos[ql]])return (col[pos[ql]]==k)?qr-ql+1:0; for(int i=ql;i<=qr;i++)res+=(a[i]==k); return res; } if(~col[pos[ql]])res+=(col[pos[ql]]==k)?R[pos[ql]]-ql+1:0; else for(int i=ql;i<=R[pos[ql]];i++)res+=(a[i]==k); if(~col[pos[qr]])res+=(col[pos[qr]]==k)?qr-L[pos[qr]]+1:0; else for(int i=L[pos[qr]];i<=qr;i++)res+=(a[i]==k); if(pos[ql]+1<=pos[qr]-1) for(int i=pos[ql]+1;i<=pos[qr]-1;i++) { if(~col[i]){res+=(col[i]==k)?R[i]-L[i]+1:0;continue;} for(int j=L[i];j<=R[i];j++)res+=(a[j]==k); } return res; } inline void change(int ql,int qr,int k) { if(pos[ql]==pos[qr]) { down(pos[ql]); for(int i=ql;i<=qr;i++)a[i]=k; reset(pos[ql],k); return; } down(pos[ql]); for(int i=ql;i<=R[pos[ql]];i++)a[i]=k; reset(pos[ql],k); down(pos[qr]); for(int i=L[pos[qr]];i<=qr;i++)a[i]=k; reset(pos[qr],k); if(pos[ql]+1<=pos[qr]-1)for(int i=pos[ql]+1;i<=pos[qr]-1;i++)col[i]=k; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); t=sqrt(n),cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; for(int i=1;i<=cnt;i++)col[i]=-1; for(int i=1;i<=n;i++) { int l,r,k;scanf("%d%d%d",&l,&r,&k); printf("%d\n",query(l,r,k)); change(l,r,k); } return 0; }
9.区间最小众数
与这题相同。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=100010; const int maxt=10100; const int inf=1e9; int n,t,cnt,num; int a[maxn],b[maxn],c[maxn],L[maxt],R[maxt],pos[maxn]; int ans[maxt][maxt]; vector<int>ve[maxn]; inline int read() { char c=getchar();int res=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar(); return res*f; } inline void pre_work() { sort(b+1,b+n+1);num=unique(b+1,b+n+1)-(b+1);b[0]=inf; for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+num+1,a[i])-b; for(int i=1;i<=n;i++)ve[a[i]].push_back(i); for(int i=1;i<=cnt;i++) { int maxx=0,res=0; for(int j=L[i];j<=n;j++) { c[a[j]]++; if(c[a[j]]>maxx||(c[a[j]]==maxx&&b[a[j]]<b[res]))res=a[j],maxx=c[a[j]]; if(j%t==0||j==n)ans[i][pos[j]]=res; } for(int j=L[i];j<=n;j++)c[a[j]]--; } } inline int calc(int ql,int qr,int k) { return upper_bound(ve[k].begin(),ve[k].end(),qr)-lower_bound(ve[k].begin(),ve[k].end(),ql); } inline int query(int ql,int qr) { int maxx=0,res=0; if(pos[ql]==pos[qr]) { for(int i=ql;i<=qr;i++) { int tmp=calc(ql,qr,a[i]); if(tmp>maxx||(tmp==maxx&&b[a[i]]<b[res]))maxx=tmp,res=a[i]; } return res; } for(int i=ql;i<=R[pos[ql]];i++) { int tmp=calc(ql,qr,a[i]); if(tmp>maxx||(tmp==maxx&&b[a[i]]<b[res]))maxx=tmp,res=a[i]; } for(int i=L[pos[qr]];i<=qr;i++) { int tmp=calc(ql,qr,a[i]); if(tmp>maxx||(tmp==maxx&&b[a[i]]<b[res]))maxx=tmp,res=a[i]; } int p1=pos[ql]+1,p2=pos[qr]-1; if(p1<=p2) { int tmp=calc(ql,qr,ans[p1][p2]); if(tmp>maxx||(tmp==maxx&&b[ans[p1][p2]]<b[res]))maxx=tmp,res=ans[p1][p2]; } return res; } int main() { n=read(); for(int i=1;i<=n;i++)a[i]=b[i]=read(); t=30;cnt=n/t; if(n%t)cnt++; for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n); for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1; pre_work(); for(int i=1;i<=n;i++) { int l=read(),r=read(); printf("%d\n",b[query(l,r)]); } return 0; }