• 线段树求后继+环——cf1237D


    /*
    首先开三倍消环(两倍是不够的),倒序求值,线段树找一下后继即可 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 300005
    
    int n,a[N],ans[N];
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    int Max[N<<2],Min[N<<2],pos1,pos2;
    void build(int l,int r,int rt){
        Max[rt]=0;Min[rt]=1e9+7;
        if(l==r){
            Max[rt]=Min[rt]=a[l];
            return;
        }
        int m=l+r>>1;
        build(lson);build(rson);
        Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
        Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
    }
    void query1(int L,int R,int v,int l,int r,int rt){//找第一个比v大的后继
        if(l==r){
            if(Max[rt]>v)pos1=min(pos1,l);
            return;
        } 
        int m=l+r>>1;
        if(L<=l && R>=r){//可以在区间里二分了 
            if(Max[rt<<1]>v)
                query1(L,R,v,lson);
            else if(Max[rt<<1|1]>v)
                query1(L,R,v,rson);
            return;
        }
        if(L<=m)query1(L,R,v,lson);
        if(R>m)query1(L,R,v,rson); 
    }
    void query2(int L,int R,double v,int l,int r,int rt){//找第一个比v小的后继 
        if(l==r){
            if(Min[rt]<v)pos2=min(pos2,l);
            return;
        }
        int m=l+r>>1;
        if(L<=l && R>=r){
            if(Min[rt<<1]<v)
                query2(L,R,v,lson);
            else if(Min[rt<<1|1]<v)
                query2(L,R,v,rson);
            return;
        }
        if(L<=m)query2(L,R,v,lson);
        if(R>m)query2(L,R,v,rson);
    } 
    
    int main(){
        cin>>n;
        int mx=0,mi=0x3f3f3f3f;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            a[i+n]=a[i+2*n]=a[i];
            mx=max(mx,a[i]);
            mi=min(mi,a[i]);
        }
        
        if(mx<=mi*2){
            for(int i=1;i<=n;i++)cout<<-1<<" ";
            return 0;
        }
        
        build(1,3*n,1);
        ans[3*n]=1;
        for(int i=3*n-1;i>=1;i--){
            pos1=pos2=3*n+1;
            query1(i+1,2*n,a[i],1,3*n,1);//找第一个大于a[i]的位置
            query2(i+1,3*n,1.0*a[i]/2,1,3*n,1);//找第一个小于a[i]/2的位置 
            if(pos1==3*n+1 && pos2==3*n+1)//后面都可行 
                ans[i]=3*n-i+1; 
            else if(pos1==3*n+1)//后面没有比a[i]大的 
                ans[i]=pos2-i; 
            else if(pos2==3*n+1)//后面没有比a[i]/2小的 
                ans[i]=ans[pos1]+pos1-i;
            else if(pos1<pos2)//大的在小的前面
                ans[i]=ans[pos1]+pos1-i;
            else if(pos1>pos2)
                ans[i]=pos2-i; 
        }
        for(int i=1;i<=n;i++)
            cout<<ans[i]<<" ";
    } 
  • 相关阅读:
    【Win 10 应用开发】获取本机的IP地址
    【Win 10应用开发】延迟共享
    【Win 10 应用开发】共享目标(UWP)
    【Win 10应用开发】响应系统回退键的导航事件
    编写Windows服务疑问2:探索服务与安装器的关系
    编写Windows服务疑问1:操作过程
    服务器常见错误代码500、501、502、503、504、505
    git reset与git revert的区别
    Redis集群方案怎么做?
    ThinkPHP设计模式与Trait技术
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11727773.html
Copyright © 2020-2023  润新知