• 牛客练习赛28 B 数据结构


    题目描述:

    qn姐姐最好了~

        qn姐姐给你了一个长度为n的序列还有m次操作让你玩,

        1 l r 询问区间[l,r]内的元素和

        2 l r 询问区间[l,r]内的元素的平方 

        3 l r x 将区间[l,r]内的每一个元素都乘上x

        4 l r x 将区间[l,r]内的每一个元素都加上x

    输入描述:

    第一行两个数n,m
    
    接下来一行n个数表示初始序列
    
    就下来m行每行第一个数为操作方法opt,
    
    若opt=1或者opt=2,则之后跟着两个数为l,r
    
    若opt=3或者opt=4,则之后跟着三个数为l,r,x
    
    操作意思为题目描述里说的

    输出描述:

    对于每一个操作1,2,输出一行表示答案

    示例1

    输入

    5 6
    1 2 3 4 5
    1 1 5
    2 1 5
    3 1 2 1
    4 1 3 2
    1 1 4
    2 2 3

    输出

    15
    55
    16
    41

    备注:

    对于100%的数据 n=10000,m=200000 (注意是等于号)
    
    保证所有询问的答案在long long 范围内

    出题人题解:

    显然,线段树
    记录4个东西,区间和tree[root][0],区间平方和 tree[root][1],乘法懒标记 add2[root],加法懒标记add1[root] 。
    查询的话就是常规查询,打标记就是线段树2板子一样,
    初值:add1[root]=0,add2[root]=1;
    加法:add1[root]+=dx
    乘法:add2[root]*=dx;
    然后考虑更新答案
    当前区间[l,r] ,当前节点root,这里面每个元素都变成了( a[i]为更新后, x[i]为更新前)

    所以

    利用线段树处理区间和与区间平方和
    利用性质(a+b)^2(a+b)^2=a^2+2ab+b^2   ,(ab)^2=a^2b^2  可判断出区间平方和的变动情况,然后进行修改。
    区间和的话比较容易了,
    然后lazy有点麻烦

    然后就标准线段树板子

    线段树模板:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxn 10005
    #define lson l,mid,root<<1
    #define rson mid+1,r,root<<1|1
    long long n,m,tree[maxn<<2][2],add1[maxn<<2],add2[maxn<<2];
    
    void pushup(long long root)
    {
        tree[root][0]=tree[root<<1][0]+tree[root<<1|1][0];
        tree[root][1]=tree[root<<1][1]+tree[root<<1|1][1];
    }
    void pushdown1(long long l,long long r,long long root)
    {  //加法下推
        if(add1[root])
        {
            add1[root<<1]+=add1[root];  //+号不能少,切记
            add1[root<<1|1]+=add1[root];
            long long x=tree[root<<1][0];
            long long y=tree[root<<1|1][0];
            tree[root<<1][0]+=l*add1[root];
            tree[root<<1|1][0]+=r*add1[root];
            tree[root<<1][1]+=2*x*add1[root]+l*add1[root]*add1[root];
            tree[root<<1|1][1]+=2*y*add1[root]+r*add1[root]*add1[root];
            add1[root]=0;
        }
    }
    void pushdown2(long long l,long long r,long long root)
    {  //乘法下推
        if(add2[root]!=1)
        {
            add2[root<<1]*=add2[root];  //*号不能少,切记
            add2[root<<1|1]*=add2[root];
            tree[root<<1][0]*=add2[root];
            tree[root<<1|1][0]*=add2[root];
            tree[root<<1][1]*=add2[root]*add2[root];
            tree[root<<1|1][1]*=add2[root]*add2[root];
            add2[root]=1;
        }
    }
    void build(long long l,long long r,long long root)
    {
        add1[root]=0;
        add2[root]=1;
        if(l==r)
        {
            scanf("%lld",&tree[root][0]);
            tree[root][1]=tree[root][0]*tree[root][0];
            return;
        }
        long long mid=(l+r)>>1;
        build(lson);
        build(rson);
        pushup(root);
    }
    void update1(long long L,long long R,long long C,long long l,long long r,long long root)
    {  //加法更新
        if(L<=l&&r<=R)
        {
            long long x=tree[root][0];
            tree[root][0] += (r-l+1)*C;
            tree[root][1] += 2*x*C+(r-l+1)*C*C;
            add1[root] += C;
            return ;
        }
        long long mid = (l+r)/2;
        pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
        if(L<=mid)
            update1(L,R,C,lson);
        if(R>mid)
             update1(L,R,C,rson);
        pushup(root);
    }
    void update2(long long L,long long R,long long C,long long l,long long r,long long root)
    {  //乘法更新
        if(L<=l&&r<=R)
        {
            tree[root][0] *= C;
            tree[root][1] *= C*C;
            add2[root] *= C;  if(add1[root]) add1[root] *= C;
            return ;
        }
        long long mid = (l+r)/2;
        pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
        if(L<=mid)
            update2(L,R,C,lson);
        if(R>mid)
             update2(L,R,C,rson);
        pushup(root);
    }
    long long query(long long L,long long R,long long c,long long l,long long r,long long root)
    {
        if(L<=l&&R>=r)
        {
            if(c==1)
                return tree[root][0];
            if(c==2)
                return tree[root][1];
        }
        long long ans=0,mid=(l+r)>>1;
        pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
        if(L<=mid)
            ans+=query(L,R,c,lson);
        if(R>mid)
            ans+=query(L,R,c,rson);
        return ans;
    }
    
    int main()
    {
        cin>>n>>m;
        build(1,n,1);
        while(m--)
        {
            long long op,x,y,val;
            scanf("%lld",&op);
            if(op==1||op==2)
            {
                scanf("%lld%lld",&x,&y);
                printf("%lld
    ",query(x,y,op,1,n,1));
            }
            else if(op==3||op==4)
            {
                scanf("%lld%lld%lld",&x,&y,&val);
                if(op==3)
                    update2(x,y,val,1,n,1);
                else
                    update1(x,y,val,1,n,1);
            }
        }
        return 0;
    }

    转自:题解

    第二种。。。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define N 100005
    
    using namespace std;
    typedef long long LL;
    
    struct Node
    {
        LL lazy, mulzy, sum, mul;
    }tree[N];
    LL a[10005];
    int n, m;
    void Build(int G, int l, int r)
    {
        if (l == r)
        {
            tree[G].mulzy = 1,
            tree[G].sum = a[l],
            tree[G].mul = a[l] * a[l];
            return;
        }
        int mid = (l + r) >> 1;
        Build(G * 2, l, mid);
        Build(G * 2 + 1, mid + 1, r);
        tree[G].mulzy = 1;
        tree[G].sum = tree[G * 2].sum + tree[G * 2 + 1].sum;
        tree[G].mul = tree[G * 2].mul + tree[G * 2 + 1].mul;
    }
    void Updata(int p, int l, int r)
    {
        if (tree[p].lazy == 0 && tree[p].mulzy == 1)
        return;
        int mid = (l + r) >> 1;
        tree[p * 2].mul = tree[p * 2].mul * tree[p].mulzy * tree[p].mulzy + 2 * (tree[p].mulzy * tree[p].lazy) * tree[p * 2].sum + (mid - l + 1) * tree[p].lazy * tree[p].lazy;
        tree[p * 2 + 1].mul = tree[p * 2 + 1].mul * tree[p].mulzy * tree[p].mulzy + 2 * (tree[p].mulzy * tree[p].lazy) * tree[p * 2 + 1].sum + (r - mid) * tree[p].lazy * tree[p].lazy;
        tree[p * 2].sum = tree[p * 2].sum * tree[p].mulzy + (mid - l + 1) * tree[p].lazy;
        tree[p * 2 + 1].sum = tree[p * 2 + 1].sum * tree[p].mulzy + (r - mid) * tree[p].lazy; tree[p * 2].mulzy = tree[p * 2].mulzy * tree[p].mulzy;
        tree[p * 2 + 1].mulzy = tree[p * 2 + 1].mulzy * tree[p].mulzy;
        tree[p * 2].lazy = tree[p * 2].lazy * tree[p].mulzy + tree[p].lazy;
        tree[p * 2 + 1].lazy = tree[p * 2 + 1].lazy * tree[p].mulzy + tree[p].lazy;
        tree[p].lazy = 0, tree[p].mulzy = 1;
    }
    void Insert(int p, int l, int r, int a, int b, LL x, int opt)
    {
        int mid = (l + r) >> 1;
        if (l == a && r == b)
        {
            if (opt == 3)
            tree[p].mul = tree[p].mul * x * x,
            tree[p].sum = tree[p].sum * x,
            tree[p].lazy *= x, tree[p].mulzy *= x;
            else
            tree[p].mul += 2 * x * tree[p].sum + (r - l + 1) * x * x, tree[p].sum = tree[p].sum + (r - l + 1) * x, tree[p].lazy += x;
            return;
        }
        Updata(p,l,r);
        if (mid >= b)
        Insert(p * 2, l, mid, a, b, x, opt);
        else if (a > mid)
        Insert(p * 2 + 1, mid + 1, r, a, b, x, opt);
        else
        {
            Insert(p * 2, l, mid, a, mid, x, opt);
            Insert(p * 2 + 1, mid + 1, r, mid + 1, b, x, opt);
        }
        tree[p].sum = tree[p * 2].sum + tree[p * 2 + 1].sum;
        tree[p].mul = tree[p * 2].mul + tree[p * 2 + 1].mul;
    }
    LL Get_sum(int p, int l, int r, int a, int b, int opt)
    {
        int mid = (l + r) >> 1;
        if (l == a && r == b)
        {
            if (opt == 1)
            return tree[p].sum;
            else return tree[p].mul;
        }
        Updata(p, l, r);
        if (mid >= b)
        return Get_sum(p * 2, l, mid, a, b, opt);
        else if (a > mid)
        return Get_sum(p * 2 + 1, mid + 1, r, a, b, opt);
        else return Get_sum(p * 2, l, mid, a, mid, opt) + Get_sum(p * 2 + 1, mid + 1, r, mid + 1, b, opt);
    }
    int main()
    {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
        Build(1, 1, n);
        for (int i = 1; i <= m; i++)
        {
            int opt, l, r;
            LL x;
            scanf("%d", &opt);
            if (opt == 1 || opt == 2)
            {
                scanf("%d %d", &l, &r);
                printf("%lld
    ", Get_sum(1, 1, n, l, r, opt));
            }
            if (opt == 3 || opt == 4)
            {
                scanf("%d %d %lld", &l, &r, &x);
                Insert(1, 1, n, l, r, x, opt);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    java之数组使用以及拓展
    Java之数组介绍
    方法
    break&continue
    networkmanager is not running 网络管理没有运行
    CentOS-7修改IP
    操作系统
    计算机基础理论
    编码和解码
    pyQuery库
  • 原文地址:https://www.cnblogs.com/lu1nacy/p/10016629.html
Copyright © 2020-2023  润新知