这个跨度可以说是最大的一个了,从2017年的期中考试时开始看,一直到2018年去完福州还没啃完。。现在我终于会啦,线段树是个好东西。恩
因为线段树也就都那样吧,反正dalao的博客多得是,这里我就不解释了
T1
题目详见题库P6T1
给定一个包含n个数的序列,初值全为0,现对这个序列有两种操作
操作1:把给定第x个数改为y
操作2:查询从第x个数到第y个数得最大值
#include<bits/stdc++.h>
using namespace std;
long long n,x,y,maxx[400010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void change(long long l,long long r,long long o)
{
if (x<l||x>r) return;
if (l==r)
{
maxx[o]=y;
return;
}
long long mid=(l+r)/2;
change(l,mid,o*2);
change(mid+1,r,o*2+1);
maxx[o]=max(maxx[o*2],maxx[o*2+1]);
}
long long find(long long l,long long r,long long o)
{
if (x>r||y<l) return -1;
if (x<=l&&y>=r) return maxx[o];
long long mid=(l+r)/2;
long long tl=find(l,mid,o*2);
long long tr=find(mid+1,r,o*2+1);
return max(tl,tr);
}
int main()
{
n=read();
for (int i=1;i<=n;++i)
{
int d=read();
if (d==1)
{
x=read();
y=read();
change(1,n,1);
}
if (d==2)
{
x=read();
y=read();
printf("%lld\n",find(1,n,1));
}
}
return 0;
}
T2
题目详见题库P6T2
给定一个包含n个数的序列,初值全为0,现对这个序列有两种操作
操作1:将第x个数到第y个数加1
操作2:查询从第x个数到第y个数得最大值
#include<bits/stdc++.h>
using namespace std;
long long n,x,y,maxx[400010],add[400010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void pushdown(long long o)
{
maxx[o*2]+=add[o];
maxx[o*2+1]+=add[o];
add[o*2]+=add[o];
add[o*2+1]+=add[o];
add[o]=0;
}
void jia(long long l,long long r,long long o)
{
if (x>r||y<l) return;
if (x<=l&&y>=r)
{
add[o]++;
maxx[o]++;
return;
}
pushdown(o);
long long mid=(l+r)/2;
if (x<=mid) jia(l,mid,o*2);
if (y>mid) jia(mid+1,r,o*2+1);
maxx[o]=max(maxx[o*2],maxx[o*2+1]);
}
long long find(long long l,long long r,long long o)
{
if (x>r||y<l) return -1;
if (x<=l&&y>=r) return maxx[o];
pushdown(o);
long long mid=(l+r)/2;
long long tl=find(l,mid,o*2);
long long tr=find(mid+1,r,o*2+1);
return max(tl,tr);
}
int main()
{
n=read();
for (int i=1;i<=n;++i)
{
int d=read();
if (d==1)
{
x=read();
y=read();
jia(1,n,1);
}
if (d==2)
{
x=read();
y=read();
printf("%lld\n",find(1,n,1));
}
}
return 0;
}
T3
题目详见luogu3372
https://www.luogu.org/problemnew/show/P3372
如题,已知一个数列,你需要进行下面两种操作
1.将某区间每一个数加上v
2.求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
long long n,m,x,y,v,a[400010],sum[400010],add[400010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void build(long long l,long long r,long long o)
{
add[o]=0;
if (l==r)
{
sum[o]=a[l];
return;
}
long long mid=(l+r)/2;
build(l,mid,o*2);
build(mid+1,r,o*2+1);
sum[o]=sum[o*2]+sum[o*2+1];
}
void pushdown(long long o,long long k)
{
sum[o*2]+=add[o]*(k-(k/2));
sum[o*2+1]+=add[o]*(k/2);
add[o*2]+=add[o];
add[o*2+1]+=add[o];
add[o]=0;
}
void jia(long long l,long long r,long long o)
{
if (x<=l&&y>=r)
{
add[o]+=v;
sum[o]+=v*(r-l+1);
return;
}
pushdown(o,r-l+1);
long long mid=(l+r)/2;
if (x<=mid) jia(l,mid,o*2);
if (y>mid) jia(mid+1,r,o*2+1);
sum[o]=sum[o*2]+sum[o*2+1];
}
long long find(long long l,long long r,long long o)
{
if (x<=l&&y>=r) return sum[o];
pushdown(o,r-l+1);
long long mid=(l+r)/2;
long long ans=0;
if (x<=mid) ans+=find(l,mid,o*2);
if (y>mid) ans+=find(mid+1,r,o*2+1);
sum[o]=sum[o*2]+sum[o*2+1];
return ans;
}
int main()
{
n=read();
m=read();
for (int i=1;i<=n;++i)
a[i]=read();
build(1,n,1);
for (int i=1;i<=m;++i)
{
int d=read();
if (d==1)
{
x=read();
y=read();
v=read();
jia(1,n,1);
}
if (d==2)
{
x=read();
y=read();
printf("%lld\n",find(1,n,1));
}
}
return 0;
}
T4(终极)
题目详见luogu3373
https://www.luogu.org/problemnew/show/P3373
如题,已知一个数列,你需要进行下面三种操作
1.将某区间每一个数乘上v
2.将某区间每一个数加上v
3.求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
long long n,m,p,x,y,v,a[400010],sum[400010],mul[400010],add[400010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void build(long long l,long long r,long long o)
{
mul[o]=1;
add[o]=0;
if (l==r)
{
sum[o]=a[l]%p;
return;
}
long long mid=(l+r)/2;
build(l,mid,o*2);
build(mid+1,r,o*2+1);
sum[o]=(sum[o*2]+sum[o*2+1])%p;
}
void pushdown(long long o,long long k)
{
sum[o*2]=(sum[o*2]*mul[o]+add[o]*(k-(k/2)))%p;
sum[o*2+1]=(sum[o*2+1]*mul[o]+add[o]*(k/2))%p;
mul[o*2]=(mul[o*2]*mul[o])%p;
mul[o*2+1]=(mul[o*2+1]*mul[o])%p;
add[o*2]=(add[o*2]*mul[o]+add[o])%p;
add[o*2+1]=(add[o*2+1]*mul[o]+add[o])%p;
mul[o]=1;
add[o]=0;
}
void cheng(long long l,long long r,long long o)
{
if (x<=l&&y>=r)
{
mul[o]=(mul[o]*v)%p;
add[o]=(add[o]*v)%p;
sum[o]=(sum[o]*v)%p;
return;
}
pushdown(o,r-l+1);
long long mid=(l+r)/2;
if (x<=mid) cheng(l,mid,o*2);
if (y>mid) cheng(mid+1,r,o*2+1);
sum[o]=(sum[o*2]+sum[o*2+1])%p;
}
void jia(long long l,long long r,long long o)
{
if (x<=l&&y>=r)
{
add[o]=(add[o]+v)%p;
sum[o]=(sum[o]+v*(r-l+1))%p;
return;
}
pushdown(o,r-l+1);
long long mid=(l+r)/2;
if (x<=mid) jia(l,mid,o*2);
if (y>mid) jia(mid+1,r,o*2+1);
sum[o]=(sum[o*2]+sum[o*2+1])%p;
}
long long find(long long l,long long r,long long o)
{
if (x<=l&&y>=r) return sum[o]%p;
pushdown(o,r-l+1);
long long mid=(l+r)/2;
long long ans=0;
if (x<=mid) ans=(ans+find(l,mid,o*2))%p;
if (y>mid) ans=(ans+find(mid+1,r,o*2+1))%p;
sum[o]=(sum[o*2]+sum[o*2+1])%p;
return ans%p;
}
int main()
{
n=read();
m=read();
p=read();
for (int i=1;i<=n;++i)
a[i]=read();
build(1,n,1);
for (int i=1;i<=m;++i)
{
int d=read();
if (d==1)
{
x=read();
y=read();
v=read();
cheng(1,n,1);
}
if (d==2)
{
x=read();
y=read();
v=read();
jia(1,n,1);
}
if (d==3)
{
x=read();
y=read();
printf("%lld\n",find(1,n,1));
}
}
return 0;
}
另外,再次友情链接一下
http://blog.youkuaiyun.com/qq_39670434/article/details/78079339