现在的位置: 首页 > 算法 > 正文

poj 3468 A Simple Problem with Integers(线段树区区)

2018年09月22日 算法 ⁄ 共 2259字 ⁄ 字号 评论关闭

题目链接:  http://poj.org/problem?id=3468

题目大意:  给出N个数,和M次查询

                 C a b c  区间[a,b]的值都加上c

                 Q a b     查询区间[a,b]值的和

解题思路:  线段树区间lazy延迟更新,每次插入区间标记lazy

                 下次再操作此区间时用lazy更新下面的子树

                  每个结点存储值是区间的和

                  更新和查询的时间复杂度都是O(logN)

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 201000
#define MID(a,b) (a+b)>>1
#define L(a) a<<1
#define R(a) (a<<1|1)
typedef struct{
    int left,right;
    long long int sum,add;
}Node;

Node Tree[MAX<<2]={0};
long long int num[MAX];

void Build(long long int t,int l,int r)             //以1为根节点建立线段树[l,r]
{
    Tree[t].left=l,Tree[t].right=r;
    if(Tree[t].left==Tree[t].right)
    {
        Tree[t].sum=num[Tree[t].right];
        Tree[t].add=0;
        return ;
    }
    int mid=MID(Tree[t].left,Tree[t].right);
    Build(L(t),l,mid);
    Build(R(t),mid+1,r);
    Tree[t].sum=Tree[L(t)].sum+Tree[R(t)].sum;
}

void Insert(long long int t,int l,int r,long long int m)   //向区间[l,r]插入m
{
    if(Tree[t].left==l&&Tree[t].right==r)
    {
        Tree[t].sum+=(Tree[t].right-Tree[t].left+1)*m;
        Tree[t].add+=m;
        return ;
    }
    if(Tree[t].add!=0)                   //无论是插入还是查询都要更新lazy
    {
        Tree[L(t)].sum+=(Tree[L(t)].right-Tree[L(t)].left+1)*Tree[t].add;
        Tree[R(t)].sum+=(Tree[R(t)].right-Tree[R(t)].left+1)*Tree[t].add;
        Tree[L(t)].add+=Tree[t].add;
        Tree[R(t)].add+=Tree[t].add;
        Tree[t].add=0;
    }
    int mid=MID(Tree[t].left,Tree[t].right);
    if(l>mid)
    {
        Insert(R(t),l,r,m);
    }
    else if(r<=mid)
    {
        Insert(L(t),l,r,m);
    }
    else
    {
        Insert(L(t),l,mid,m);
        Insert(R(t),mid+1,r,m);
    }
    Tree[t].sum=Tree[L(t)].sum+Tree[R(t)].sum;
}

long long int Query(long long int t,int l,int r)     //查询区间[a,b]
{
    if(Tree[t].left==l&&Tree[t].right==r)
    {
        return Tree[t].sum;
    }
    if(Tree[t].add!=0)                 //lazy更新
    {
        Tree[L(t)].sum+=(Tree[L(t)].right-Tree[L(t)].left+1)*Tree[t].add;
        Tree[R(t)].sum+=(Tree[R(t)].right-Tree[R(t)].left+1)*Tree[t].add;
        Tree[L(t)].add+=Tree[t].add;
        Tree[R(t)].add+=Tree[t].add;
        Tree[t].add=0;
    }
    int mid=MID(Tree[t].left,Tree[t].right);
    if(l>mid)
    {
        return Query(R(t),l,r);
    }
    else if(r<=mid)
    {
        return Query(L(t),l,r);
    }
    else
    {
        return Query(L(t),l,mid)+Query(R(t),mid+1,r);
    }
    Tree[t].sum=Tree[L(t)].sum+Tree[R(t)].sum;   //更新结点: 结点的值=左子树+右子树
}

int main()
{
    char ch;
    int n,a,b,c;
    long long int i,m;
    scanf("%d%lld",&n,&m);
    for(i=1;i<=n;i++)         //初始化输入
        scanf("%lld",&num[i]);
    Build(1,1,n);
    for(i=1;i<=m;i++)
    {
        getchar();
        scanf("%c",&ch);
        if(ch=='C')
        {
            scanf("%d%d%d",&a,&b,&c);
            Insert(1,a,b,c);            //区间[a,b]都加上c
        }
        else
        {
            scanf("%d%d",&a,&b);
            printf("%lld\n",Query(1,a,b));  //查询区间[a,b]的和
        }
    }
    return 0;
}

注:原创文章,转载请注明出处

抱歉!评论已关闭.