2018 icpc徐州站网络赛 H ——Ryuji doesn't want to study ——(线段树)

题目链接:https://nanti.jisuanke.com/t/31460

题目思路:很明显的一个线段树题目,但是要求的是a[l]*len+a[l+1]*(len-1)+a[l+2]*(len-2)+......+a[r],所以根据这个推得以下公式:sum[l,r]=\sum _{i=l}^{r}a[i]*(n-l+1)-(n-r)*\sum_{i=l}^{r}a[i]

可以试着推一下这个公式。所以我们维护两个线段树,sum1保存正常的数组区间和,sum2保存a[i]*i的数组的区间和,

当查询区间为[l,r]时,答案就是sum2[l,r]-(n-r)*sum1[l,r]

代码和思路参考于:https://blog.csdn.net/ccsu_cat/article/details/82594389

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

/*
    维护两个线段树sum1和sum2,sum1维护正常区间和,sum2维护(n-i+1)*a[i]的区间和
    答案就是smu2[l,r]-(n-r)sum1[l,r]
    公式可以自己推一下
*/
const int maxn=1e5+10;
typedef long long ll;
ll sum1[maxn*4],sum2[maxn*4],a[maxn];//线段树开4倍空间
int n;
void build(int o,int l,int r)
{
    if(l==r)
    {
        sum1[o]=a[l];
        sum2[o]=a[l]*(n-l+1);
        return;
    }
    int ls=o*2,rs=o*2+1,m=(l+r)/2;//左右子节点和中间节点
    build(ls,l,m);
    build(rs,m+1,r);
    sum1[o]=sum1[ls]+sum1[rs];
    sum2[o]=sum2[ls]+sum2[rs];
}

//查询sum1
ll query1(int o,int l,int r,int ql,int qr)
{
    if(l>=ql&&r<=qr)return sum1[o];
    int ls=2*o,rs=2*o+1,m=(l+r)/2;
    ll res=0;
    if(ql<=m)res+=query1(ls,l,m,ql,qr);
    if(qr>m)res+=query1(rs,m+1,r,ql,qr);
    return res;
}
//查询sum2
ll query2(int o,int l,int r,int ql,int qr)
{
    if(l>=ql&&r<=qr)return sum2[o];
    int ls=2*o,rs=2*o+1,m=(l+r)/2;
    ll res=0;
    if(ql<=m)res+=query2(ls,l,m,ql,qr);
    if(qr>m)res+=query2(rs,m+1,r,ql,qr);
    return res;
}
//更新
void update(int o,int l,int r,int k,ll v)
{
    if(l==r)
	{
		sum1[o]=v;
		sum2[o]=v*(n-l+1);
		return;
	}
	int ls=o*2,rs=o*2+1,m=(l+r)/2;
	if(k<=m)update(ls,l,m,k,v);
	else update(rs,m+1,r,k,v);
	sum1[o]=sum1[ls]+sum1[rs];
	sum2[o]=sum2[ls]+sum2[rs];
}

int main()
{
    int q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
        }
        build(1,1,n);
        while(q--)
        {
            int x;
            scanf("%d",&x);
            if(x==1)
            {
                int l,r;
                scanf("%d%d",&l,&r);
                ll temp1=query1(1,1,n,l,r);
                ll temp2=query2(1,1,n,l,r);
                ll temp3=n-r;
                printf("%lld\n",temp2-temp3*temp1);
            }
            else
            {
                int k;
                ll v;
                scanf("%d%lld",&k,&v);
                update(1,1,n,k,v);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Q755100802/article/details/83030927