2019icpc徐州網絡賽E.XKC's basketball team(權值線段樹)

https://nanti.jisuanke.com/t/41387

題意:給你一個n,m,n個人都有一個Wi權值,問你每個人的右面最遠的一個Wj大於等於Wi+m的位置與這個人的位置中間有多少人

(j>i,Wj>=Wi+m);

題解:在每個 i 的右面找大於等於Wi+m的最遠位置,用權值線段樹倒着維護下標,查詢一次,更新一次。偶對了,離散化。

細節:1.倒着做,是因爲正着一次全插入後找不到 i 後面比他的大的,會有影響,所以倒着做

           2.寫查詢是按普通線段樹寫,查【k,len】(離散化後)內大於Wi+m的,因爲是在權值線段樹中找大於某個數的

           3.離散化這個一定要注意,如果Wi+m沒在離散化數組出現過,    那就是從大於等於該數的下標-len,開始找,是正確的,比如  說1 3 5 7 9 ,找大於4的就是從下標3開始找。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int n,m; 
int a[maxn];
int mx[maxn*4];
vector<int>v;
int getid(int x){
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void build(int l,int r,int p){
	 if(l==r) {
	 	mx[p]=0;
	 	return ;
	 }
	 int mid=(l+r)/2;
	 build(l,mid,p<<1);
	 build(mid+1,r,p<<1|1);
}
void update(int l,int r,int id,int pos,int p){
	if(l==r){
		mx[p]=max(mx[p],pos);
		return ;
	}
	int mid=(l+r)/2;
	if(id<=mid) update(l,mid,id,pos,p<<1);
	else update(mid+1,r,id,pos,p<<1|1);
	mx[p]=max(mx[p<<1],mx[p<<1|1]);
}
int quert(int l,int r,int L,int R,int p){
	if(L<=l&&r<=R){
		return mx[p];
	}
	int mid=(l+r)/2;
	int res=0;
	if(L<=mid) res=max(res,quert(l,mid,L,R,p<<1));
	if(R>mid) res=max(res,quert(mid+1,r,L,R,p<<1|1));
	return res;
}
int ans[maxn];
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		v.push_back(a[i]);
	}
	sort(v.begin(),v.end());
	int len=v.size();
	build(1,len,1);
	for(int i=n;i>=1;i--){
		int p=quert(1,len,getid(a[i]+m),len,1);//返回的就是下標 
		//cout<<getid(a[i]+m)<<" "<<p<<endl;
		if(p==0) ans[i]=-1;
		else  ans[i]=p-i-1;
		update(1,len,getid(a[i]),i,1);
	}
	ans[n]=-1;
	for(int i=1;i<=n;i++){
		if(i<n) 
		cout<<ans[i]<<" ";
		else cout<<ans[i]<<endl;
	}
	return 0;
} 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章