马上就要 csp \texttt{csp} csp了, 树状数组和线段树肯定是复习不可少的一部分。今天作者来整理一下它们的模板。
I.
\texttt{I.}
I.单点修改,区间查询。
例题:P3374
代码:
#include
using namespace std;
#define lid id*2
#define rid id*2+1
const int N=5e6+7;
int n,m;
int a[N];
struct sa{
int l;
int r;
int sum;
}tree[N<<1];
void build(int id,int l,int r){
tree[id].l=l,tree[id].r=r;
if(l==r){
tree[id].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
tree[id].sum=tree[lid].sum+tree[rid].sum;
return;
}
int search(int id,int l,int r){
if(tree[id].l>r||tree[id].r<l)return 0;
if(tree[id].l>=l&&tree[id].r<=r){
return tree[id].sum;
}
int s=0;
if(tree[lid].r>=l){
s+=search(lid,l,r);
}
if(tree[rid].l<=r){
s+=search(rid,l,r);
}
return s;
}
void add(int id,int x,int w){
if(tree[id].l==tree[id].r){
tree[id].sum+=w;
return;
}
int mid=(tree[id].l+tree[id].r)>>1;
if(x<=mid)add(lid,x,w);
else add(rid,x,w);
tree[id].sum=tree[lid].sum+tree[rid].sum;
return;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
while(m--){
int op,x,y;
cin>>op>>x>>y;
if(op==1){
add(1,x,y);
}
else{
cout<<search(1,x,y)<<'\n';
}
}
return 0;
}
II.
\texttt{II.}
II.区间修改,单点查询。
例题:P3368
代码:
#include
using namespace std;
void sleep(int p);int read();int read(int p);
#define ll long long
#define ull unsigned long long
#define db double
#define lid id*2
#define rid id*2+1
const int N=3e6+7,inf=0x3f3f3f3f,mod=1e9+7;
struct sa{
int sum;
int l,r;
}tree[N];
int n,ans;
int a[N];
void build(int id,int l,int r){
tree[id].l=l,tree[id].r=r;
if(l==r){
tree[id].sum=a[l];
return ;
}
int mid=l+r>>1;
build(lid,l,mid);
build(rid,mid+1,r);
return;
}
void modify(int id,int l,int r,int k){
if(tree[id].l>=l&&tree[id].r<=r){
tree[id].sum+=k;
return;
}
if(tree[id].l>r||tree[id].r<l)return;
int mid=tree[id].l+tree[id].r>>1;
if(mid>=l)modify(lid,l,r,k);
if(mid<r)modify(rid,l,r,k);
return;
}
void query(int id,int dis){
ans+=tree[id].sum;
if(tree[id].l==tree[id].r)
return;
int mid=tree[id].l+tree[id].r>>1;
if(dis<=mid)query(lid,dis);
else query(rid,dis);
return ;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
while(m--){
int c;
cin>>c;
if(c==1){
int x,y,z;
cin>>x>>y>>z;
modify(1,x,y,z);
}
else{
ans=0;
int x;cin>>x;
query(1,x);
cout<<ans<<'\n';
}
}
return 0;
}
III.
\texttt{III.}
III.区间修改,区间查询
例题:P3372
代码:
#include
using namespace std;
#define lid id*2
#define rid id*2+1
const long long N=5e5+7;
long long n,m;
long long a[N];
struct sa{
long long l,r,sum;
long long lz;
}tree[N];
void build(long long id,long long l,long long r){
tree[id].l=l,tree[id].r=r,tree[id].lz=0;
if(l==r){
tree[id].sum=a[l];
return;
}
long long mid=l+r>>1;
build(lid,l,mid);
build(rid,mid+1,r);
tree[id].sum=tree[lid].sum+tree[rid].sum;
return;
}
void push_down(long long id){
if(!tree[id].lz)return ;
long long mid=tree[id].l+tree[id].r>>1;
tree[lid].lz+=tree[id].lz;
tree[lid].sum+=(mid-tree[id].l+1)*tree[id].lz;
tree[rid].lz+=tree[id].lz;
tree[rid].sum+=(tree[rid].r-mid)*tree[id].lz;
tree[id].lz=0;
return;
}
void update(long long id,long long l,long long r,long long k){
if(tree[id].r<=r&&tree[id].l>=l){
tree[id].sum+=k*(tree[id].r-tree[id].l+1);
tree[id].lz+=k;
return;
}
push_down(id);
long long mid=tree[id].l+tree[id].r>>1;
if(l<=mid)update(lid,l,r,k);
if(mid<r)update(rid,l,r,k);
tree[id].sum=tree[lid].sum+tree[rid].sum;
return;
}
long long search(long long id,long long l,long long r){
if(tree[id].l>=l&&tree[id].r<=r)
return tree[id].sum;
if(tree[id].r<l|tree[id].l>r)return 0;
push_down(id);
long long s=0;
if(tree[lid].r>=l)s+=search(lid,l,r);
if(tree[rid].l<=r)s+=search(rid,l,r);
return s;
}
int main(){
cin>>n>>m;
for(long long i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
while(m--){
long long x,y,z,k;
cin>>x>>y>>z;
if(x==1){
cin>>k;
update(1,y,z,k);
}
else{
cout<<search(1,y,z)<<'\n';
}
}
return 0;
}
IV.
\texttt{IV.}
IV.区间加法、乘法,区间查询。
例题:P3373
代码:
#include
using namespace std;
void sleep(int p);long long read();int read(long long p);
#define lid id*2
#define rid id*2+1
typedef long long ll;
#define ull unsigned long long
#define db double
const int N=5e5+5,inf=0x3f3f3f3f,mod=1e9+7;
int n,m;
ll p;
ll a[N];
struct sa{
ll l,r;
ll sum,add,mul;
}tree[N];
inline void init(int id){
tree[id].sum%=p,tree[id].mul%=p,tree[id].sum%=p;
return;
}
void build(int id,ll l,ll r){
tree[id].l=l,tree[id].r=r,tree[id].mul=1;
if(l==r){
tree[id].sum=a[l]%p;
return;
}
int mid=tree[id].l+tree[id].r>>1;
build(lid,l,mid);build(rid,mid+1,r);
tree[id].sum=tree[lid].sum+tree[rid].sum;
tree[id].sum%=p;
return;
}
void push_down(int id){
int mul=tree[id].mul,add=tree[id].add;
tree[lid].sum=tree[lid].sum*mul+add*(tree[lid].r-tree[lid].l+1);
tree[rid].sum=tree[rid].sum*mul+add*(tree[rid].r-tree[rid].l+1);
tree[lid].mul*=mul,tree[rid].mul*=mul;
tree[lid].add=(tree[lid].add*mul+add)%p;
tree[rid].add=(tree[rid].add*mul+add)%p;
tree[id].mul=1,tree[id].add=0;
init(lid),init(rid);
return;
}
void update(int id,bool op,ll l,ll r,ll k){
if(tree[id].l>=l&&tree[id].r<=r){
if(op){
tree[id].mul*=k;
tree[id].add*=k;
tree[id].sum*=k;
init(id);
}
else{
tree[id].sum+=(tree[id].r-tree[id].l+1)*k%p;
tree[id].add+=k;
init(id);
}
return;
}
push_down(id);
ll mid=tree[id].l+tree[id].r>>1;
if(mid>=l)update(lid,op,l,r,k);
if(mid+1<=r)update(rid,op,l,r,k);
tree[id].sum=(tree[lid].sum+tree[rid].sum)%p;
return;
}
ll query(int id,int l,int r){
if(tree[id].l>=l&&tree[id].r<=r){
return tree[id].sum;
}
if(tree[id].l>r||tree[id].r<l)return 0;
push_down(id);
int mid=tree[id].l+tree[id].r>>1;ll s=0;
if(mid>=l)s+=query(lid,l,r);
if(mid+1<=r)s+=query(rid,l,r);
return s%p;
}
int main()
{
cin>>n>>m>>p;
for(int i=1;i<=n;i++){
a[i]=read();a[i]%=p;
}
build(1,1,n);
while(m--){
ll x=read(),y=read(),z=read(),k;
if(x==1){
k=read();k%=p;
update(1,1,y,z,k);
}else
if(x==2){
k=read();k%=p;
update(1,0,y,z,k);
}else{
printf("%lld\n",query(1,y,z));
}
}
return 0;
}
void sleep(int p){for(int i=1;i<=p*100000;i++)int x;return;}
inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline int read(long long p){long long x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();x=x%p;}return x*f;}
I.
\texttt{I.}
I.单点修改,区间查询。
例题:P3374
代码:
#include
using namespace std;
#define ll long long
#define ull unsigned long long
const int N=6e5+5,mod=1e9+7;
inline void sleep(int p);
inline int read();
inline int read(int mod);
int n,m;
int a[N];
int c[N];
int lbt(int x){return x & -x;}
void add(int x,int k){
for(;x<=n;x+=lbt(x))c[x]+=k;
return;
}
int ask(int x){
int t=0;
for(;x;x-=lbt(x))t+=c[x];
return t;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
add(i,a[i]);
}
while(m--){
int op;
cin>>op;
if(op==1){
int x,k;
cin>>x>>k;
add(x,k);
}
else{
int l,r;
cin>>l>>r;
cout<<ask(r)-ask(l-1)<<'\n';
}
}
return 0;
}
inline void sleep(int p){for(int i=1;i<=100000*p;i++)int x;return;}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline int read(int p){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();x=x%p;}return x*f;}
II.
\texttt{II.}
II.区间修改,单点查询。
例题:P3368
代码:
#include
using namespace std;
#define ll long long
#define ull unsigned long long
const int N=6e5+5,mod=1e9+7;
inline void sleep(int p);
inline int read();
inline int read(int mod);
int n,m;
int a[N];
int b[N];
int c[N];
int lbt(int x){return x & -x;}
void add(int x,int k){
for(;x<=n;x+=lbt(x))c[x]+=k;
return;
}
int ask(int x){
int t=0;
for(;x;x-=lbt(x))t+=c[x];
return t;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i]-a[i-1];
add(i,b[i]);
}
while(m--){
int op;
cin>>op;
if(op==1){
int l,r,x;
cin>>l>>r>>x;
add(l,x);
if(r<n)add(r+1,-x);
}
else{
int l;
cin>>l;
cout<<ask(l)<<'\n';
}
}
return 0;
}
inline void sleep(int p){for(int i=1;i<=100000*p;i++)int x;return;}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline int read(int p){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();x=x%p;}return x*f;}
III.
\texttt{III.}
III.区间修改,区间查询。
例题:P3372
代码:
#include
using namespace std;
#define ll long long
#define ull unsigned long long
#define int long long
const int N=7e5+5,mod=1e9+7;
inline void sleep(int p);
inline int read();
inline int read(int mod);
int n,m;
int a[N];
int b[N];
int c[2][N];
void add(int op,int x,int k){
for(;x<=n;x+=x&-x)c[op][x]+=k;
return;
}
int ask(int op,int x){
int t=0;
for(;x;x-=x&-x)t+=c[op][x];
return t;
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1]+a[i];
}
while(m--){
int op;
cin>>op;
if(op==1){
int l,r,d;
cin>>l>>r>>d;
add(0,l,d);
add(0,r+1,-d);
add(1,l,d*l);
add(1,r+1,-d*(r+1));
}
else{
int l,r;
cin>>l>>r;
int ans=b[r]+(r+1)*ask(0,r)-ask(1,r);
ans-=b[l-1]+l*ask(0,l-1)-ask(1,l-1);
cout<<ans<<'\n';
}
}
return 0;
}
inline void sleep(int p){for(int i=1;i<=100000*p;i++)int x;return;}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline int read(int p){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();x=x%p;}return x*f;}
希望大家看了这篇博文后,能有更多的进步。如果想进一步提升 OI \texttt{OI} OI 水平,可以做一下这道题,本人原创。