zoukankan      html  css  js  c++  java
  • AcWing1277维护序列(线段树)

    题目地址https://www.acwing.com/problem/content/description/1279/

    题目描述

    老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。

    有长为 N 的数列,不妨设为 a1,a2,,aN

    有如下三种操作形式:

    1. 把数列中的一段数全部乘一个值;
    2. 把数列中的一段数全部加一个值;
    3. 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP 的值。

    输入格式

    第一行两个整数 N 和 P

    第二行含有 NN 个非负整数,从左到右依次为 a1,a2,,aN

    第三行有一个整数 M,表示操作总数;

    从第四行开始每行描述一个操作,输入的操作有以下三种形式:

    • 操作 11:1 t g c,表示把所有满足 tig 的 ai 改为 ai×c
    • 操作 22:2 t g c,表示把所有满足 tig 的 ai改为 ai+c
    • 操作 33:3 t g,询问所有满足 tig 的 ai的和模 P的值。

    同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

    输出格式

    对每个操作 3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

    数据范围

    1N,M1e5
    1tgN,
    0c,ai1e9,
    1P1e9

    题解:这是一道典型的线段树问题。但是这里对于区间修改涉及两个操作。我们可以使用一个巧妙的办法来解决。假设一个区间的懒标记:add=a,mult=b.那么又来一个add1,则该区间的变换为sum+=(tr[u].r-tr[u].l+1)*add1,add+=add1.如果来一个mult1,则该区间的变换为sum*=mult1,mult*=mult1,add*=mult1.

    剩下的就可以利用线段树直接完成了。

    AC代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1e5+10;
    #define ll long long int
    ll n,m,p;
    struct node{
        int l,r;
        ll sum,add,mult;
    }tr[4*N];
    
    void pushup(int u){
        tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
    }
    
    void build(int u,int l,int r){
        tr[u].l=l,tr[u].r=r,tr[u].add=0,tr[u].mult=1;
        if(l==r){
            scanf("%lld",&tr[u].sum);
            tr[u].sum%=p;
            return ;
        }
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
        return ;
    }
    
    void pushnow(int u,ll add,ll mult){
        tr[u].sum*=mult;
        tr[u].sum%=p;
        tr[u].sum+=add*(tr[u].r+1-tr[u].l);
        tr[u].sum%=p;
        tr[u].mult*=mult;
        tr[u].add*=mult;
        tr[u].add%=p;
        tr[u].add+=add;
        tr[u].mult%=p;
        tr[u].add%=p;
    }
    
    void pushdown(int u){
        if(tr[u].add!=0||tr[u].mult!=1){
            pushnow(u<<1,tr[u].add,tr[u].mult);
            pushnow(u<<1|1,tr[u].add,tr[u].mult);
            tr[u].add=0;
            tr[u].mult=1;
        }
    }
    
    void modify(int u,int l,int r,ll add,ll mult){
        if(tr[u].l>=l&&tr[u].r<=r){
            pushnow(u,add,mult);
            return ;
        }
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid) modify(u<<1,l,r,add,mult);
        if(r>mid) modify(u<<1|1,l,r,add,mult);
        pushup(u);
        return ;
    }
    
    ll query(int u,int l,int r){
        if(tr[u].l>=l&&tr[u].r<=r) {
            return tr[u].sum%p;
        }
        int mid=tr[u].l+tr[u].r>>1;
        ll sum=0;
        pushdown(u);
        if(l<=mid) sum=query(u<<1,l,r);
        if(r>mid) sum+=query(u<<1|1,l,r);
        return sum%p; 
    }
    
    int main(){
        cin>>n>>p;
        build(1,1,n);
        cin>>m;
        ll k,l,r,c;
        while(m--){
            scanf("%lld%lld%lld",&k,&l,&r);
            if(k==1){
                scanf("%lld",&c);
                modify(1,l,r,0,c%p);
            }
            else if(k==2){
                scanf("%lld",&c);
                modify(1,l,r,c%p,1);
            }
            else {
                cout<<query(1,l,r)<<endl;
            }
        }
        return 0;
    } 

    写于;202/8/29 22:08


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    python基础:内置函数zip,map,filter
    python基础:网络编程
    python基础:异常捕捉
    jQuery demo
    day14 jQuery
    day13 JS Dom
    页面垂直方向出现两个滚动条问题?
    修复npm ERR! cb()never called!的错误;This is an error with npm itself. Please report this error at:
    vue——解决“You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file. ” eslint报错,取消文件的rules
    原型链
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13583731.html
Copyright © 2011-2022 走看看