线段树

这个跨度可以说是最大的一个了,从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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值