CF#510 (Div. 2) D(前缀和,逆序数)

CF#510 Div.2 D. Petya and Array(前缀和,逆序数)

题目链接:http://codeforces.com/contest/1042/problem/D

题目大意:区间中选择一些连续的区间,满足 ,然后看有多少个这样的区间。

思路:满足条件sum[r]-sum[l-1]<t。然后移项得:sum[l-1]>sum[r]-t;因为我们只用枚举sum[l-1],找到符合要求的sum[r],然后这个区间中所有的sum[k](k∈[l,r])都是符合要求的。所以我们只用对sum数组排序,然后对于每个sum[l],求和sum[l-1]之后减去sum[l]即可。因为数据元素比较大且含有负数,所以离散成1~n个数之后在进行查找。

用一个数据结构来维护元素的数量。

两种方法,1.树状数组 2.权值线段树(刚学的)

树状数组ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
#define M_P(a,b) make_pair(a,b)
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double EPS=1.0e-8;
const double PI=acos(-1.0);

int tree[MAXN];
ll a[MAXN],sum[MAXN];
ll n,t,ecnt;


int get_r(ll res){
	int l=1,r=ecnt,mid;
	while(l<=r){//find the last r to sum[l-1]>sum[r]-t  => res>sum[r]
		mid=(l+r)>>1;
//		cout<<l<<" "<<r<<" => ";
		if(res>sum[mid]) l=mid+1;
		else r=mid-1;
//		cout<<l<<" "<<r<<endl;
	}return r;
}
int get_l(ll res){
	int l=1,r=ecnt,mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(res==sum[mid]) return mid;
		else if(res>sum[mid]) l=mid+1;
		else r=mid-1;
	}
}
int Lowbit(int i){
	return i&(-i);
}
void Updata(int i,int x){
	while(i<=n){
		tree[i]+=x;
		i+=Lowbit(i);
	}
}
int Query(int x){
	int sum=0;
	while(x>0){
		sum+=tree[x];
		x-=Lowbit(x);
	}return sum;
}
int main(){
	scanf("%lld%lld",&n,&t);
	for(int i=1;i<=n;++i){
		scanf("%lld",&a[i]);
		sum[i]=sum[i-1]+a[i];
	}sort(sum+1,sum+1+n);
	for(int i=1;i<=n;++i){
		sum[i]=sum[i]-t;
	}sort(sum+1,sum+1+n);ecnt=n;
	for(int i=1;i<=ecnt;++i){//????? + insert 
		Updata(i,1);
	}
	ll ans=0,res=0;
	for(int i=1;i<=n;++i){
		// now res is sum[l-1]
		int r=get_r(res);
//		cout<<res<<" : "<<r<<" "<<Query(r)<<" || ";
		ans+=Query(r);
		res+=a[i];//??????? 
		int l=get_l(res-t);
		Updata(l,-1);
	}printf("%lld\n",ans);
}

权值线段树ACCode:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
 
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<time.h>
 
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
 
#define ll long long
#define Pair pair<ll,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double EPS=1.0e-8;
const double PI=acos(-1.0);

ll Tree[MAXN<<2];
ll a[MAXN],sum[MAXN];
ll n,t;

int get_r(ll res){
	int l=1,r=n,mid;
	while(l<=r){//find the last r to sum[l-1]>sum[r]-t  => res>sum[r]
		mid=(l+r)>>1;
		if(res>sum[mid]) l=mid+1;
		else r=mid-1;
	}return r;
}
int get_l(ll res){
	int l=1,r=n,mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(res==sum[mid]) return mid;
		else if(res>sum[mid]) l=mid+1;
		else r=mid-1;
	}
}
void Update(int l,int r,int x,int oper,int rt){//修改一个点 
	if(l==r){
		Tree[rt]+=oper;
		return ;
	}int mid=(l+r)>>1;
	if(x<=mid) Update(l,mid,x,oper,rt<<1);
	else Update(mid+1,r,x,oper,rt<<1|1);
	Tree[rt]=Tree[rt<<1]+Tree[rt<<1|1];
}
int Query(int ql,int qr,int l,int r,int rt){
	if(qr==0) return 0;
	if(l>=ql&&r<=qr){
		return Tree[rt];
	}int mid=(l+r)>>1;
	int ans=0;
	if(ql<=mid) ans+=Query(ql,qr,l,mid,rt<<1);
	if(qr>mid) ans+=Query(ql,qr,mid+1,r,rt<<1|1);
	return ans;
}
int main(){
	while(~scanf("%lld%lld",&n,&t)){
		clean(Tree,0);
		for(int i=1;i<=n;++i){
			scanf("%lld",&a[i]);
			sum[i]=sum[i-1]+a[i];
		}sort(sum+1,sum+1+n);
		for(int i=1;i<=n;++i){
			sum[i]=sum[i]-t;
		}sort(sum+1,sum+1+n);
		for(int i=1;i<=n;++i){
			Update(1,n,i,1,1);
		}ll ans=0,res=0;
		for(int i=1;i<=n;++i){
			int r=get_r(res);
//			cout<<r<<" : ";
			ans+=Query(1,r,1,n,1);
//			cout<<ans<<" ";
			res+=a[i];
			int l=get_l(res-t);
			Update(1,n,l,-1,1);
		}printf("%lld\n",ans);
	}
}
/*

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值