Balanced Playlist,CFGLR5D,线段树

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Deep_Kevin/article/details/102613359

正题

      Portal

      题面大意就是从每一个点开始往右走,可以走当且仅当下一个点权的两倍大于等于前面的最大值。

      问每一个点出发的路径长度。

      枚举i考虑什么样的点会在i点停下来,先让找到第一个在i点前面且比i的两倍大的第一个点。

      这个东西可以用线段树来维护。

      考虑在这里暂停的点一定会经过那个点,发现这个值是对一个区间产生贡献的,把整个复制为原来的三倍就可以了。

      关于区间的事情用一个可删堆来维护就可以了。

#include<bits/stdc++.h>
#define ls now<<1
#define rs now<<1|1
using namespace std;
 
const int N=100010;
vector<int> A[N*3],D[N*3];
priority_queue<int,vector<int>,greater<int> > f;
bool we[N*3];
int a[N];
int mmax[N*3],ans[N];
int n,m;
 
void build(int now,int l,int r){
	if(l==r) {mmax[now]=a[l];return ;}
	int mid=(l+r)/2;
	build(ls,l,mid);build(rs,mid+1,r);
	mmax[now]=max(mmax[ls],mmax[rs]);
}
 
int get_mmax(int now,int x,int y,int l,int r){
	if(x==l && y==r) return mmax[now];
	int mid=(l+r)/2;
	if(y<=mid) return get_mmax(ls,x,y,l,mid);
	else if(mid<x) return get_mmax(rs,x,y,mid+1,r);
	else return max(get_mmax(ls,x,mid,l,mid),get_mmax(rs,mid+1,y,mid+1,r));
}
 
int find_mmax(int now,int x,int y,int l,int r,int num){
	if(r<l) return 0; 
	if(l==r) return mmax[now]>=num?l:0;
	int mid=(l+r)/2;
	if(y<=mid) return find_mmax(ls,x,y,l,mid,num);
	else if(mid<x) return find_mmax(rs,x,y,mid+1,r,num);
	else {
		if(get_mmax(rs,mid+1,y,mid+1,r)>=num) return find_mmax(rs,mid+1,y,mid+1,r,num);
		else return find_mmax(ls,x,mid,l,mid,num);
	}
}
 
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]);ans[i]=1e9;
		m=max(m,a[i]);
	}
	bool tf=true;
	for(int i=1;i<=n;i++) if(a[i]*2<m) {tf=false;break;}
	if(tf){
		for(int i=1;i<=n;i++) printf("-1 ");
		return 0;	
	}
	build(1,1,n);
	for(int i=1;i<=n;i++){
		int x=find_mmax(1,1,i-1,1,n,2*a[i]+1);
		if(!x) x=find_mmax(1,i+1,n,1,n,2*a[i]+1);
		if(x){
			if(x<i) A[n+x+1].push_back(2*n+i),D[2*n+x+1].push_back(2*n+i);
			else A[x+1].push_back(2*n+i),D[n+x+1].push_back(2*n+i);
		}
	}
	for(int i=1;i<=3*n;i++){
		for(int j=0;j<A[i].size();j++) f.push(A[i][j]),we[A[i][j]]=true;
		for(int j=0;j<D[i].size();j++) we[D[i][j]]=false;
		while(!f.empty()){
			int x=f.top();
			if(!we[x]){
				f.pop();
				continue;
			}
			ans[i%n==0?n:i%n]=min(ans[i%n==0?n:i%n],x-i);
			break;
		}
	}
	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/102613359