线段树,,,(有意思的东西)
区间修改&区间查询
模板题:区间修改&区间查询
#include<bits/stdc++.h>
#define LL long long
#define sea 1100000
using namespace std;
LL q,n,kk,x,y,xx,yy,s,ans;
struct tree {LL l,r,w,f;}tr[4*sea];
inline LL read()
{
LL s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
void build(LL ll,LL rr,LL k)//建树
{
tr[k].l=ll,tr[k].r=rr;
if(ll==rr)
{
scanf("%lld",&tr[k].w);
return ;
}
LL mid=(ll+rr)/2;
build(ll,mid,k*2);
build(mid+1,rr,k*2+1);
tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
void down(LL k)//下放更新
{
tr[k*2].f+=tr[k].f;//更新左子树标记
tr[k*2+1].f+=tr[k].f;//更新右子树标记
tr[k*2].w+=tr[k].f*(tr[k*2].r-tr[k*2].l+1);//左子树的值
tr[k*2+1].w+=tr[k].f*(tr[k*2+1].r-tr[k*2+1].l+1);//更新右子树的值
tr[k].f=0;//切记要清零父亲的懒标记
}
void ask(LL k)
{
if(tr[k].l>=xx&&tr[k].r<=yy)
{
ans+=tr[k].w;//修改
return ;
}
if(tr[k].f) down(k);
LL mid=(tr[k].l+tr[k].r)/2;
if(xx<=mid) ask(k*2);
if(yy>mid) ask(k*2+1);
}
void change(LL k)
{
if(tr[k].l>=x&&tr[k].r<=y)
{
tr[k].w+=kk*(tr[k].r-tr[k].l+1);
tr[k].f+=kk;
return ;
}
if(tr[k].f) down(k);
LL mid=(tr[k].l+tr[k].r)/2;
if(x<=mid) change(k*2);
if(y>mid) change(k*2+1);
tr[k].w=tr[k*2].w+tr[k*2+1].w;// 对值的更新
}
int main()
{
n=read(); q=read();
build(1,n,1);//建树
for(LL i=1;i<=q;i++)
{
s=read();
ans=0;
if(s==1)//区间修改
{
x=read(); y=read(); kk=read();
change(1);
}
else //区间查询
{
xx=read(); yy=read();
ask(1);
printf("%lld\n",ans);
}
}
return 0;
}
区间修改(加乘)
模板题:区间修改(加乘)
#include<bits/stdc++.h>
#define sea 100010
#define LL long long
#define left l,mid,k<<1
#define right mid+1,r,k<<1|1
#define lef k<<1
#define rig k<<1|1
using namespace std;
int n,m,p,s,x,y;
long long sum[sea*4],kk,lazy_ad[sea*4],lazy_mu[sea*4];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
while(ch<='9'&&ch>='0') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline LL read_ll()//傻掉的我自己,为什么不用scanf~~~(算了不改了)
{
LL s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
while(ch<='9'&&ch>='0') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void build(int l,int r,int k)//建树
{
lazy_mu[k]=1;//乘最初为一
if(l==r) sum[k]=read_ll();
else
{
int mid=(l+r)>>1;
build(left); build(right);
sum[k]=(sum[lef]+sum[rig])%p;//
}
return ;
}
void push(int l,int r,int k,LL a,LL b)//标记
{
lazy_ad[k]=(lazy_ad[k]*b+a)%p;
lazy_mu[k]=(lazy_mu[k]*b)%p;
sum[k]=(sum[k]*b+(r-l+1)*a)%p;
}
void down(int l,int r,int k)//下放
{
int mid=(l+r)>>1;
push(left,lazy_ad[k],lazy_mu[k]);
push(right,lazy_ad[k],lazy_mu[k]);
lazy_ad[k]=0; lazy_mu[k]=1;
return ;
}
void midefy(int l,int r,int k,LL a,LL b)//加乘一块用了
{
if(x<=l&&r<=y) push(l,r,k,a,b);
elsstation
{
if(lazy_ad[k]!=0||lazy_mu[k]!=1) down(l,r,k);
int mid=(l+r)>>1;
if(x<=mid) midefy(left,a,b);
if(y>mid) midefy(right,a,b);
sum[k]=(sum[lef]+sum[rig])%p;
}
return ;
}
LL ask(int l,int r,int k)//询问
{
if(x<=l&&r<=y) return sum[k];
if(lazy_ad[k]!=0||lazy_mu[k]!=1) down(l,r,k);
int mid=(l+r)>>1;
LL ans=0;
if(x<=mid) ans=(ans+ask(left))%p;
if(y>mid) ans=(ans+ask(right))%p;
return ans;
}
int main()
{
n=read(); m=read(); p=read();
build(1,n,1);
while(m--)
{
s=read();
if(s==1)//区间加
{
x=read(); y=read(); kk=read_ll();
midefy(1,n,1,0,kk);
}
else if(s==2)//区间乘
{
x=read(); y=read(); kk=read_ll();
midefy(1,n,1,kk,1);
}
else//询问
{
x=read(); y=read();
printf("%lld\n",ask(1,n,1));
}
}
return 0;
}
单点修改&单点查询
板子题就不找了,代码还是要有的。。
// 单点修改
void alter_one(int k)
{
if(tr[k].l==tr[k].r)
{
tr[k].w+=kk;
return ;
}
int mid=(tr[k].l+tr[k].r)>>1;
if(x<=mid) alter_one(k*2);
else alter_one(k*2+1);
tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
//单点查询
int ask(int k)
{
if(tr[k].l==tr[k].r)
{
ans+=tr[k].w;
return ;
}
int mid=(tr[k].l+tr[k].r)>>1;
if(x<=mid) ask(k*2);
else ask(k*2+1);
return ans;
}
具体例题呢,,,,等学完分块再说吧( ̄∇ ̄)