D. Balanced Playlist
思路:
第一种情况:先找出最大值 再找出最小值,要是最大值 小于等于最小值的2倍(maxn<=2minn)所有元素都可以无限循环下去 输出-1.
第二中情况:我们可用线段树 ,线段树有三个值 maxn(区间最大值) minn(区间最小值) ok(此区间是否合法);
要判断此区间是否合法 先判断右子树的最小值的2倍是否大于等于左子树 即(tree[2node+1].minn2>=tree[2node].maxn)是的话ok=1,
否ok=0。
然后枚举1到n 在二分查询是否合法 即(I 到 I+m 的区间是否合法)要是合法l=m+1 否则r=m;
难点: 线段树 回溯的时候要注意 当ok=0的时候就不用在判断了 否则在判断右子树的ok 要是都不等于在判断最大值与最小值。
在查询的时候 l 到 r 每次查询的节点在进行判断是否合法 然后再将查询的节点ok的值相乘 就可以了
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
struct node{
int minn,maxn,ok;
}tree[4*N];
int last_max=0,n,a[N],maxn,minn=INT_MAX;
#define lson 2*node
#define rson 2*node+1
#define m (l+r)/2
void push_down(int node){
tree[node].maxn=max(tree[lson].maxn,tree[rson].maxn);
tree[node].minn=min(tree[lson].minn,tree[rson].minn);
if(tree[lson].ok==0){
tree[node].ok=0;
}else if(tree[rson].ok==0){
tree[node].ok=0;
}else if(tree[lson].maxn>2*tree[rson].minn){
tree[node].ok=0;
}else{
tree[node].ok=1;
}
}
void update(int v,int pos,int l,int r,int node){
if(l==r){
tree[node].maxn=tree[node].minn=v;
tree[node].ok=1;
return;
}
if(pos<=m)update(v,pos,l,m,lson);
else update(v,pos,m+1,r,rson);
push_down(node);
}
bool query(int ql,int qr,int l,int r,int node){
if(ql<=l&&qr>=r){
int f=0;
if(last_max==0){
f=tree[node].ok;
}else if(tree[node].ok==0){
f=0;
}else if(tree[node].minn*2>=last_max){
f=1;
}else if(tree[node].minn*2<last_max){
f=0;
}
last_max=max(last_max,tree[node].maxn);
return f;
}
int ans=1;
if(ql<=m)ans*=query(ql,qr,l,m,lson);
if(qr>m)ans*=query(ql,qr,m+1,r,rson);
return ans;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
maxn=max(maxn,a[i]);
minn=min(minn,a[i]);
}
if(maxn<=2*minn){
for(int i=1;i<=n;i++)printf("-1 ");
}else{
for(int i=0;i<3*n;i++){
update(a[i%n],i+1,1,3*n,1);
}
for(int i=1;i<=n;i++){
int l=1,r=2*n-1;
while(l<r){
last_max=0;
if(query(i,i+m,1,3*n,1))l=m+1;
else r=m;
}
printf("%d ",l);
}
}
}