zoukankan      html  css  js  c++  java
  • 牛客练习赛28B (经典)【线段树】

    <题目链接>

    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,输出一行表示答案

    输入

    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 范围内

    解题分析:
    本题主要的难点在于,对区间进行加或者乘上一个数后,如何快速的维护每个节点的sum 和pfh(区间所有数平方和) 值,如果仅仅是对区间的每个节点进行暴力单点更新的话,毫无疑问会超时。所以我们必须对区间整体修改,而且我们要想到,在区间的维度上,是可以对该区间的每个数平方和进行修改的,它并不像开根号一样,必须要下放到每个叶子节点,对具体的数进行开根。区间修改pfh值时,只需要利用平方和展开式,就能很容易的对区间平方和进行修改。
    
    
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 #define Lson rt<<1,l,mid
      7 #define Rson rt<<1|1,mid+1,r
      8 typedef long long ll;
      9 const int M = 1e4+10;
     10 ll n,m,arr[M];
     11 struct Tree{
     12     ll sum,pfh,add,mul;
     13 }tr[M<<2];
     14 void Pushup(ll rt){
     15     tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
     16     tr[rt].pfh=tr[rt<<1].pfh+tr[rt<<1|1].pfh;  //pfh记录的是该区间所有元素的平方和
     17 }
     18 void Pushdown(ll rt,ll len){  //mul和add相当于两个lazy标记
     19     if(tr[rt].mul!=1){
     20         ll tmp=tr[rt].mul;
     21         tr[rt<<1].sum*=tmp,tr[rt<<1|1].sum*=tmp;
     22         tr[rt<<1].pfh=tr[rt<<1].pfh*tmp*tmp,tr[rt<<1|1].pfh=tr[rt<<1|1].pfh*tmp*tmp;  //相当于对该区间的每个数都进行平方
     23         tr[rt<<1].mul*=tmp,tr[rt<<1|1].mul*=tmp;  //这几个标记都要*mul
     24         tr[rt<<1].add*=tmp,tr[rt<<1|1].add*=tmp;
     25         tr[rt].mul=1;
     26     }
     27     if(tr[rt].add){
     28         ll tmp=tr[rt].add;
     29         tr[rt<<1].pfh=tr[rt<<1].pfh+2*tmp*tr[rt<<1].sum+tmp*tmp*(len-(len>>1)); //注意这里,要将更新pfh的语句放在更新sum的语句之前      
     30         tr[rt<<1|1].pfh=tr[rt<<1|1].pfh+2*tmp*tr[rt<<1|1].sum+tmp*tmp*(len>>1);
     31         tr[rt<<1].sum+=tmp*(len-(len>>1)),tr[rt<<1|1].sum+=tmp*(len>>1);    
     32         tr[rt<<1].add+=tmp,tr[rt<<1|1].add+=tmp;
     33         tr[rt].add=0;
     34     }
     35 }
     36 void build(ll rt,ll l,ll r){
     37     tr[rt].add=0,tr[rt].mul=1;
     38     if(l==r){
     39         tr[rt].sum=arr[l],tr[rt].pfh=arr[l]*arr[l];
     40         return;
     41     }
     42     ll mid=(l+r)>>1;
     43     build(Lson);
     44     build(Rson);
     45     Pushup(rt);
     46 }
     47 void update1(ll rt,ll l,ll r,ll L,ll R,ll c){
     48     if(L<=l&&r<=R){
     49         tr[rt].sum*=c,tr[rt].add*=c,tr[rt].mul*=c;
     50         tr[rt].pfh*=tr[rt].pfh*c*c;
     51         return;
     52     }
     53     Pushdown(rt,r-l+1);
     54     ll mid=(l+r)>>1;
     55     if(L<=mid)update1(Lson,L,R,c);
     56     if(R>mid)update1(Rson,L,R,c);
     57     Pushup(rt);
     58 }
     59 void update2(ll rt,ll l,ll r,ll L,ll R,ll c){
     60     if(L<=l&&r<=R){
     61         tr[rt].pfh=tr[rt].pfh+2*c*tr[rt].sum+c*c*(r-l+1);    //注意这里,要将更新pfh的语句放在更新sum的语句之前 
     62         tr[rt].add+=c;
     63         tr[rt].sum+=c*(r-l+1);    
     64         return;
     65     }
     66     Pushdown(rt,r-l+1);
     67     ll mid=(l+r)>>1;
     68     if(L<=mid)update2(Lson,L,R,c);
     69     if(R>mid)update2(Rson,L,R,c);
     70     Pushup(rt);
     71 }
     72 ll query(ll rt,ll l,ll r,ll L,ll R,ll ty){
     73     if(L<=l&&r<=R){
     74         if(ty==1)return tr[rt].sum;
     75         else return tr[rt].pfh;
     76     }
     77     Pushdown(rt,r-l+1);
     78     ll mid=(l+r)>>1;
     79     ll ans=0;
     80     if(L<=mid)ans+=query(Lson,L,R,ty);
     81     if(R>mid)ans+=query(Rson,L,R,ty);
     82     return ans;
     83 }
     84 int main(){
     85     scanf("%lld%lld",&n,&m);
     86         for(int i=1;i<=n;i++)scanf("%lld",&arr[i]);
     87         build(1,1,n);
     88         while(m--){
     89             ll op,x,y,c;
     90             scanf("%lld%lld%lld",&op,&x,&y);
     91             if(op==1||op==2){
     92                 printf("%lld
    ",query(1,1,n,x,y,op));
     93             }
     94             else{
     95                 scanf("%lld",&c);
     96                 if(op==3)update1(1,1,n,x,y,c);
     97                 else update2(1,1,n,x,y,c);
     98             }
     99         }
    100     return 0;
    101 }
    
    


    2018-10-05
  • 相关阅读:
    2021软件工程-个人阅读作业
    OO第四单元——基于UML的UML解析器总结&OO课程总结
    OO第三单元——基于JML的社交网络总结
    OO第二单元——电梯作业总结
    SQL拼接字符串
    SQL查询列表中每种类型的第一条
    JS获取当前时间,设置不可用以前的时间
    JavaScript中的函数使用
    .Net软件开发面试技巧
    .Net小白的第一篇博客
  • 原文地址:https://www.cnblogs.com/00isok/p/9746185.html
Copyright © 2011-2022 走看看