线段树 [OpenJudge] 平方和

平方和

总时间限制: 3000ms 内存限制: 65536kB

描述

给出n(1<=n<=500000)个数字,下标从1开始

执行m(1<=m<=500000)次操作,操作可分为两种:

1 l r x:将区间[l,r]内的每个数加上x  1<=l<=r<=n -100<=x<=100

2 l r:输出区间[l,r]内每个数平方之和

输入
多组输入
第一行两个整数n m
第二行n个整数
余下m行表示m个操作意义叙述于上

输出
对应每个2操作输出相应的值
样例输入
5 3
1 1 1 1 1
2 1 5
1 1 5 1
2 1 5
样例输出
5
20

线段树成段更新
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 500005
#define ll long long

ll add[N<<2];
ll sq[N<<2];
ll sum[N<<2];

void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    sq[rt]=sq[rt<<1]+sq[rt<<1|1];
}
void pushdown(int l,int r,int rt)
{
    if(add[rt])
    {
        int m=(l+r)>>1;
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];

        sq[rt<<1]+=(2*add[rt]*sum[rt<<1]+(m-l+1)*add[rt]*add[rt]);
        sq[rt<<1|1]+=(2*add[rt]*sum[rt<<1|1]+(r-m)*add[rt]*add[rt]);

        sum[rt<<1]+=(m-l+1)*add[rt];
        sum[rt<<1|1]+=(r-m)*add[rt];
        add[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    add[rt]=0;
    if(l==r)
    {
        scanf("%d",&sum[rt]);
        sq[rt]=sum[rt]*sum[rt];
        return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}
void update(int l,int r,int rt,int L,int R,int c)
{
    if(l==L && r==R)
    {
        add[rt]+=c;
        sq[rt]+=2*sum[rt]*c+(r-l+1)*c*c;
        sum[rt]+=(r-l+1)*c;
        return;
    }
    int m=(l+r)>>1;
    pushdown(l,r,rt);
    if(R<=m) update(l,m,rt<<1,L,R,c);
    else if(L>m) update(m+1,r,rt<<1|1,L,R,c);
    else
    {
        update(l,m,rt<<1,L,m,c);
        update(m+1,r,rt<<1|1,m+1,R,c);
    }
    pushup(rt);
}
ll query(int l,int r,int rt,int L,int R)
{
    if(l==L && r==R)
    {
        return sq[rt];
    }
    int m=(l+r)>>1;
    pushdown(l,r,rt);
    if(R<=m) return query(l,m,rt<<1,L,R);
    else if(L>m) return query(m+1,r,rt<<1|1,L,R);
    else return query(l,m,rt<<1,L,m)+query(m+1,r,rt<<1|1,m+1,R);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,n,1);
        while(m--)
        {
            int op,a,b,c;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d%d",&a,&b,&c);
                update(1,n,1,a,b,c);
            }
            else
            {
                scanf("%d%d",&a,&b);
                printf("%lld\n",query(1,n,1,a,b));
            }
        }
    }
    return 0;
}

时间: 2024-08-01 21:25:45

线段树 [OpenJudge] 平方和的相关文章

OpenJudge cdqz/Data Structure Challenge 2 (Problem 5822) - 可持久化线段树

描述 给一个空数列,有M次操作,每次操作是以下三种之一: (1)在数列后加一个数 (2)求数列中某位置的值 (3)撤销掉最后进行的若干次操作(1和3) 输入 第一行一个正整数M. 接下来M行,每行开头是一个字符,若该字符为'A',则表示一个加数操作,接下来一个整数x,表示在数列后加一个整数x:若该字符为'Q',则表示一个询问操作,接下来一个整数x,表示求x位置的值:若该字符为'U',则表示一个撤销操作,接下来一个整数x,表示撤销掉最后进行的若干次操作. 输出 对每一个询问操作单独输出一行,表示答

CH Round #52 还教室[线段树 方差]

还教室 CH Round #52 - Thinking Bear #1 (NOIP模拟赛) [引子]还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教室的同学们纷纷归还自己当初租借的教室.请你来解决类似于借教室的另一个问题.[问题描述]在接受借教室请求的 n 天中,第 i 天剩余的教室为 a i 个.作为大学借教室服务的负责人,你需要完成如下三种操作共 m 次:① 第 l 天到第 r 天,每天被归还 d 个教室.② 询问第 l 天到第 r 天教室

逆序对 【线段树解法】

逆序对 [线段树解法] 求逆序对问题是一个十分经典的算法问题,通常使用归并排序解决,经gster大神指点,写出了逆序对线段树写法,顺便练了练线段树. 题目传送门:http://noi.openjudge.cn/ch0204/7622/ 代码: 1 /* 2 Segment_Tree 3 author: SHHHS 4 2016-09-28 12:35:17 5 */ 6 #include "bits/stdc++.h" 7 8 using namespace std ; 9 typed

HDU 5405 (树链剖分+线段树)

Problem Sometimes Naive 题目大意 给你一棵n个节点的树,有点权. 要求支持两种操作: 操作1:更改某个节点的权值. 操作2:给定u,v, 求 Σw[i][j]   i , j 为任意两点且i到j的路径与u到v的路径相交. 解题分析 容易发现对于一个询问,答案为总点权和的平方 减去 去掉u--v这条链后各个子树的点权和的平方的和. 开两棵线段树,tag1记录点权和,tag2记录某点的所有轻链子树的点权和的平方的和. 每次沿着重链往上走时,直接加上这条重链的所有点的tag2和

HDU4578 线段树(区间更新 + 多种操作)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578  , 线段树的区间更新 + 多种操作,好题. 虽然是比较裸的线段树,但是比较麻烦,并且有很多细节需要考虑,最后我7.3s很惊险地过了,求大神告知优化方法. 这道题坑在有三种询问:set , add , mul.所以lazy标记要有三个,如果三个标记同时出现的处理方法——当更新set操作时,就把add标记和mul标记全部取消:当更新mul操作时,如果当前节点add标记存在,就把add标记改为:a

NOJ1560---Let Slimes Grow Up(线段树)

问题描述 You know 8Mao has his own Slime Team. But he soon found that let the Slimes stand in a line and make them from low to high is a such stupid thing since the Slimes are so f[bi][bi]king stupid! As a result, 8Mao decided to give up. But 8Mao still

【BZOJ4373】算术天才⑨与等差数列 [线段树]

算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列. 当然,他还会不断修改其中的某一项. 为了不被他鄙视,你必须要快速并正确地回答完所有问题. 注意:只有一个数的数列也是等

HDU 4578 - Transformation - [加强版线段树]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2, -, an. The initial values of them are 0. There are four kinds of operations.Operation 1: Add c to each

Bailian 2808 校门外的树(入门线段树)

题目链接:http://bailian.openjudge.cn/practice/2808?lang=en_US 总时间限制: 1000ms 内存限制: 65536kB 描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,--,L,都种有一棵树.马路上有一些区域要用来建地铁,这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域