POJ 3468 A Simple Problem with Integers(线段树)

这题刚开始用的普通的累加方法,果断超时...中间做些小改变就行了,还有就是结果要用long long 



题目链接 点击打开链接


代码注释:


<strong><span style="font-size:18px;color:#ff6600;">#include<iostream>
#include<cstdio>
#define N 100000
using namespace std;
int s[N+5];
struct node
{
    int l,r;
    long long sum,n; //数比较大用 long long
} a[N*3];
void build(int l,int r,int i)
{
    a[i].l=l;
    a[i].r=r;
    a[i].n=0;
    if(l==r)
    {
        a[i].sum=s[l];
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,2*i);
    build(mid+1,r,2*i+1);
    a[i].sum=a[2*i].sum+a[2*i+1].sum;//向上更新
}
void insert(int l,int r,int c,int i)
{
    if(a[i].l==l&&a[i].r==r)
    {
        a[i].n+=c;
        return;
    }
    a[i].sum+=(long long)c*(r-l+1); //更新时把每段的总和算出来
    int mid=(a[i].l+a[i].r)/2;
    if(r<=mid)
        insert(l,r,c,2*i);
    else if(l>mid)
        insert(l,r,c,2*i+1);
    else
    {
        insert(l,mid,c,2*i);
        insert(mid+1,r,c,2*i+1);
    }
}
long long cal(int l,int r,int i)
{
    if(a[i].l==l&&a[i].r==r)
        return a[i].sum+(long long)(r-l+1)*a[i].n;
    if(a[i].n!=0)  // 本题关键就在这,相当于把权值向下传递
    {
        a[2*i].n+=a[i].n;
        a[2*i+1].n+=a[i].n;
        a[i].sum+=(long long)(a[i].r-a[i].l+1)*a[i].n;//同上算出每段的sum,最后加起来方便
        a[i].n=0;
    }
    int mid=(a[i].l+a[i].r)/2;
    if(r<=mid)
        return cal(l,r,2*i);
    else if(l>mid)
        return cal(l,r,2*i+1);
    else
        return cal(l,mid,2*i)+cal(mid+1,r,2*i+1);
}
int main()
{
    int n,m,x,y,i,c;
    while(scanf("%d%d",&n,&m)!=EOF)//用cin可能超时
    {
        for(i=1; i<=n; i++)
            scanf("%d",&s[i]);
        build(1,n,1);
        char o;
        while(m--)
        {
            getchar(); //这里不要忘了...
            scanf("%c",&o);
            if(o=='Q')
            {
                scanf("%d%d",&x,&y);
                printf("%lld\n",cal(x,y,1));
            }
            else
            {
                scanf("%d%d%d",&x,&y,&c);
                insert(x,y,c,1);
            }
        }

    }
}
</span></strong>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值