Codeforces Round #510 (Div. 2) D. Petya and Array(权值线段树or树状数组)

题目链接
在这里插入图片描述
题意:问区间和小于t的区间对数是多少?
思路:sum【j】<sum【i】+t,则问题就转化成了求【i+1,n】中小于sum【i】+t的个数,可以离散化后用权值线段树,树状数组二分也可以,不过不清楚权值线段树做法的时候v要push (sum+t)再离散化,留坑。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
const int maxn=2e5+100;
struct cxk{
	int l,r;
	ll val;
}tree[maxn<<3];
vector<ll>v;
int n;
ll t,ans=0,a[maxn],sum[maxn];
void build(int l,int r,int x)
{
	tree[x].l=l;tree[x].r=r;
	if(l==r){
		tree[x].val=0;return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
}
void update(int pos,int x)
{
	tree[x].val++;
	if(tree[x].l==tree[x].r) return ;
	int mid=(tree[x].l+tree[x].r)>>1;
	if(pos<=mid) update(pos,x<<1);
	else update(pos,x<<1|1);
}
void query(int pos,int x)
{
	if(tree[x].l==tree[x].r) return ;
	int mid=(tree[x].l+tree[x].r)>>1;
	if(mid>=pos)  query(pos,x<<1);
	else ans+=tree[x<<1].val,query(pos,x<<1|1);
}
int main()
{
	scanf("%d%lld",&n,&t);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&a[i]);
		sum[i]=sum[i-1]+a[i];
		v.push_back(sum[i]);
	}
	if(n==1)
	{
		printf("%d\n",a[1]<t?1:0);
		return 0;
	}
	for(int i=1;i<=n;++i) v.push_back(sum[i]+t);
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	int size=v.size();
	build(1,size,1);
	update(lower_bound(v.begin(),v.end(),sum[n])-v.begin()+1,1);
	for(int i=n-1;i>=0;--i)
	{
		query(lower_bound(v.begin(),v.end(),sum[i]+t)-v.begin()+1,1);
		if(i>0) update(lower_bound(v.begin(),v.end(),sum[i])-v.begin()+1,1);
	}
	printf("%lld\n",ans);
}

发布了171 篇原创文章 · 获赞 0 · 访问量 5801

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104620579
今日推荐