CODEVS 1082 (区间查询+区间求和)

题目链接:http://codevs.cn/problem/1082/

注意更新区间求和时,应该加上的是这一段区间包含的元素的个数乘以更新的值

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <cstring>
#include <map>
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 4000005;
const ll INF = 0x3f3f3f3f3f;
int dir[8][2]= {0,1,1,0,0,-1,-1,0,1,-1,-1,-1,1,1,-1,1};
int dir2[4][2]= {0,1,0,-1,1,0,-1,0};
bool flag;
ll a[maxn],sum[maxn],n,ans,num[maxn];
struct node{
    ll l;
    ll r;
}b[maxn];
void pushup(ll k)
{
    sum[k] = sum[k*2] + sum[k*2+1];
}
void build(ll k,ll l,ll r)//递归建树
{
    if(l == r)
    {
        b[k].l = l,b[k].r = r;
        sum[k] = a[l];
        return ;
    }
    else
    {
        ll mid = (l+r) / 2;
        b[k].l = l,b[k].r=r;
        build(k<<1,l,mid);
        build(k*2+1,mid+1,r);
        pushup(k);
    }
}
void pushdown(ll k)
{
    if(num[k]){
        num[k<<1] += num[k];
        num[k*2+1] += num[k];
        sum[k<<1] += (b[k*2].r-b[k*2].l+1)*num[k];
        sum[k*2+1] += (b[k*2+1].r-b[k*2+1].l+1)*num[k];
        num[k] = 0;
    }
}
void update(ll l,ll r,ll L,ll R,ll k,ll v)//单点更新
{
    if(L >= l && R <= r)
    {
        sum[k] += (b[k].r-b[k].l+1)*v;
        num[k] += v;
        return ;
    }
    else
    {
        pushdown(k);
        ll mid = (L + R) / 2;
        if(l <= mid) update(l,r,L,mid,k*2,v);
        if(mid < r) update(l,r,mid+1,R,k*2+1,v);
        pushup(k);
    }
}
void Search(ll l,ll r,ll L,ll R,ll k)//区间查询
{
    if(L >= l&& R <= r)
    {
        ans += sum[k];
        return;
    }
    pushdown(k);
    ll mid = (L + R) / 2;
    if(mid >= l)  Search(l,r,L,mid,k*2);
    if(mid < r)  Search(l,r,mid+1,R,k*2+1);
}
int main()
{
    ll m;
    cin >> n;
    for(ll i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    mem(sum);
    build(1,1,n);//建树
    ll z,x,c,s;
    cin >> m;
    for(ll i = 1; i <= m; i++)
    {
        cin >> z;
        if(z == 1)
            {
                cin >> x >> c >> s;
                update(x,c,1,n,1,s);
            }
        else
        {
           cin >> x >> c;
           ans = 0;
           Search(x,c,1,n,1);
           cout << ans << endl;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LLLAIH/p/11324260.html

时间: 2024-10-11 20:47:19

CODEVS 1082 (区间查询+区间求和)的相关文章

FOJ 2171 防守阵地 II 区间求和区间查询 线段树

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2171 题意: 给定n长序列,常数m,q个询问 对于每个询问x 1.求[x, x+m-1] 区间和 2.[x,x+m-1]区间的所有元素-1 线段树裸题,不知为何全用longlong会re,只能改成部分longlong #include<stdio.h> #include<string.h> #define ll long long #define LL int #define L(x) (x*

非递归线段树区间修改区间求和的两种实现(以POJ 3468为例)

题意:就是一个数列,支持  查询区间和  以及  区间内的数都加上 C . 递归线段树很好写,就不讲了. 递归版本        : 内存:6500K   时间:2.6 秒 非递归版本一: 内存:4272K   时间:1.1秒 非递归版本二: 内存:4272K   时间:1.3秒 -------------------------------------------------------------------------------------------------------------

HDU 1166-敌兵布阵(线段树:单点更新,区间求和)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 44361    Accepted Submission(s): 18875 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

POJ 3468 A Simple Problem with Integers(线段树模板之区间增减更新 区间求和查询)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 140120   Accepted: 43425 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type o

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是

【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵

hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define lson l,m,root<<1 5 #define rson m+1,r,root<<1|1 6 using namespace std; 7 const int MAXN=50000*

算法模板——线段树3(区间覆盖值+区间求和)

实现功能——1:区间覆盖值:2:区间求和 相比直接的区间加,这个要注重顺序,因为操作有顺序之分.所以这里面的tag应该有个pushup操作(本程序中的ext) 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b,d:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end;

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

算法模板——线段树1(区间加法+区间求和)

实现功能——1:区间加法:2:区间求和 最基础最经典的线段树模板.由于这里面操作无顺序之分,所以不需要向下pushup,直接累积即可 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min