牛客练习赛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\n",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\n", 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;
}

 

posted @ 2018-10-16 20:18  lu_nacy  阅读(219)  评论(0编辑  收藏  举报