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

题意:给定n个数和q次查询,输入a,b,c,设L为b-c+1,若a=1,则求出\sum (a[n]*(r-n+1)) (n=l....r),若a=2,则将第b个数替换成c。

思路:做题的时候发现只要求出两个值,总区间的和即\sum (a[n] (n=1....n) 以及  \sum (a[n]*(r-n+1)) (n=1....n),前者-(n-c)*后者即可。

代码如下:

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

#define ll long long

#define maxn 100000+100
ll sum[maxn<<2];
ll sum1[maxn<<2];
ll n;
void pushup(ll rt)
{
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
	sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];
}
void build(ll l,ll r,ll rt)
{
	if(l==r)
	{
		scanf("%d",&sum[rt]);
		sum1[rt]=sum[rt];
		sum[rt]*=(n-l+1);
		return;
	}
	ll m=(l+r)>>1;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	pushup(rt);
}
void update(ll q,ll change,ll l,ll r,ll rt)
{
	if(l==r)
	{
		sum[rt]=change*(n-l+1);
		sum1[rt]=change;
		return;
	}
	ll m=(l+r)>>1;
	if(q<=m)
		update(q,change,l,m,rt<<1);
	else
		update(q,change,m+1,r,rt<<1|1);
	pushup(rt);
}
ll query(ll x,ll y,ll l,ll r,ll rt)
{
	if(x<=l&&y>=r)
		return sum[rt];
	ll m=(l+r)>>1;
	ll ret=0;
	if(x<=m)
		ret+=query(x,y,l,m,rt<<1);
	if(y>m)
		ret+=query(x,y,m+1,r,rt<<1|1);
	return ret;
}
ll query1(ll x,ll y,ll l,ll r,ll rt)
{
	if(x<=l&&y>=r)
		return sum1[rt];
	ll m=(l+r)>>1;
	ll ret=0;
	if(x<=m)
		ret+=query1(x,y,l,m,rt<<1);
	if(y>m)
		ret+=query1(x,y,m+1,r,rt<<1|1);
	return ret;
}
int main()
{
	ll q;
	ll a,b,c;
	ll ans;
	while(~scanf("%lld%lld",&n,&q))
    {
        build(1,n,1);
        while(q--)
        {
            ans=0;
            scanf("%lld%lld%lld",&a,&b,&c);
            if(a==1)
            {
                ans=query(b,c,1,n,1)- (n-c)*query1(b,c,1,n,1);
                printf("%lld\n",ans);
            }
            else if(a==2)
            {
                update(b,c,1,n,1);
            }
        }
    }
	return 0;
}

线段树

猜你喜欢

转载自blog.csdn.net/ygl_6saltfish/article/details/82621749