CF433B

题目简化和分析:

为了更加快速的求出答案,好像没前缀和快速。
为了大家更好的理解线段树,我们使用了线段树。

如果您并不了解线段树,可以转战模板。
因为我们知道线段树可以快速求区间和,于是我们建两棵树。
一个是原来数组,一个是排好序的数组。
每次查询分别用不同的线段树区间和就行了。

Solution:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef double db;

const int N=4e5+50;
const int M=1e5+50;

inline ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}

ll n,m;
ll v[N];

ll ans1[N],ans2[N];
ll ls(ll x){return x<<1;}
ll rs(ll x){return x<<1|1;}
void push_up1(ll p){
	ans1[p]=ans1[ls(p)]+ans1[rs(p)];	
}
void push_up2(ll p){
	ans2[p]=ans2[ls(p)]+ans2[rs(p)];
}
void build1(ll p,ll l,ll r){
	if(l==r){ans1[p]=v[l];return;}
	ll mid=(l+r)>>1;
	build1(ls(p),l,mid);
	build1(rs(p),mid+1,r);
	push_up1(p);
}
void build2(ll p,ll l,ll r){
	if(l==r){ans2[p]=v[l];return;}
	ll mid=(l+r)>>1;
	build2(ls(p),l,mid);
	build2(rs(p),mid+1,r);
	push_up2(p);
}
ll query1(ll nx,ll ny,ll l,ll r,ll p){
	ll res=0;
	if(nx<=l&&r<=ny) return ans1[p];
	ll mid=(l+r)>>1;
	if(nx<=mid) res+=query1(nx,ny,l,mid,ls(p));
	if(ny>mid) res+=query1(nx,ny,mid+1,r,rs(p));
	return res;
}
ll query2(ll nx,ll ny,ll l,ll r,ll p){
	ll res=0;
	if(nx<=l&&r<=ny) return ans2[p];
	ll mid=(l+r)>>1;
	if(nx<=mid) res+=query2(nx,ny,l,mid,ls(p));
	if(ny>mid) res+=query2(nx,ny,mid+1,r,rs(p));
	return res;
}
int main()
{
	n=read();
	for(int i=1;i<=n;++i) v[i]=read();
	build1(1,1,n);
	sort(v+1,v+n+1);
	build2(1,1,n);
	m=read();
	for(int i=1;i<=m;++i){
		ll op,l,r;
		op=read();
		if(op==1){
			l=read(),r=read();
			printf("%lld\n",query1(l,r,1,n,1));
		}else{
			l=read(),r=read();
			printf("%lld\n",query2(l,r,1,n,1));
		}
	}
	return 0;
}

posted @ 2022-07-28 17:25  RVG  阅读(18)  评论(0)    收藏  举报