树状数组 0pts
查看原帖
树状数组 0pts
1332453
__Florie_楼主2024/11/2 12:10

就是二分卡出可以贡献的范围,进行求和。

个人觉得只是和题解的运行顺序不同罢了。

一个正序一个倒叙啊。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
#define ldb long double
template<typename T>
inline void read(T &x){
	bool f=1; x=0; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=!f; ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch-'0'); ch=getchar();}
	x=(f?x:-x); return ;
}
template<typename T>
inline void print(T x){
	if(x<0) {putchar('-'); x=-x;}
	if(x>9) print(x/10);
	putchar(x%10+'0'); return ;
}

const int N=100010;
int n,dow,upp,len,lowbit[N],sum[N],a[N],aa[N];
ll ans,s[N],ss[N],val[N];//id-->val(小到大)
map<ll,int>lev;//val-->id
void pre() {for(int i=1;i<=n;i++) lowbit[i]=(i&(-i)); lowbit[0]=100; return ;}
void uppdate(int p,int pts) {aa[p]+=pts; while(p<len) {sum[p]+=pts; p+=lowbit[p];} return ;}
int putout(int p){
	int ans=0;
	while(p) {ans+=sum[p]; p-=lowbit[p];}
	return ans;
}

signed main(){
	read(n); read(dow); read(upp); pre();
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
	for(int i=1;i<=n;i++) ss[i]=s[i];
	sort(ss+1,ss+n+1); len=unique(ss+1,ss+n+1)-ss;
	for(int i=1;i<len;i++) {lev[ss[i]]=i; val[i]=ss[i];}
	for(int i=1;i<=n;i++){//建树 
		sum[lev[s[i]]]++; aa[lev[s[i]]]++;
		if(lev[s[i]]+lowbit[lev[s[i]]]<len)
		sum[lev[s[i]]+lowbit[lev[s[i]]]]+=sum[lev[s[i]]];
	}
	for(int i=1;i<=n;i++){
		int lhs=dow+s[i-1],rhs=upp+s[i-1];
		lhs=lower_bound(val+1,val+len,lhs)-val;
		rhs=upper_bound(val+1,val+len,rhs)-val-1;
		//if(lhs>=len||val[rhs]>upp+s[i-1]) continue;
		//树状数组中[lhs,rhs]的和即为当前所求 
		ans=ans+putout(rhs)-putout(lhs-1);
		uppdate(lev[s[i]],-1);
		//cout<<lhs<<":"<<rhs<<"?"<<ans<<'\n';
	}
	print(ans);
	return 0;
}
2024/11/2 12:10
加载中...