F. Array Partition(Codeforces Round #686 (Div. 3))

F. Array Partition(Codeforces Round #686 (Div. 3))

Codeforces Round #686 (Div. 3)

枚举第一段区间。得到一个max值。

再对第三段区间进行二分,很显然区间越大max越大,满足单调性。

二分得到满足条件的一段区间l到r。

最后再l-1到r-1区间二分满足第二段区间的答案。

两种二分方法

1.二分+线段树RMQ

二分区间,用线段树RMQ进行判断 时间 复杂度为\(O(nlog^2n)\)

2.线段树上二分

首先找到二分区间,然后再线段树上判断左右子节点。时间复杂度为\(O(nlogn)\)

方法一:

#include <iostream>
#define lch 2*k
#define rch 2*k+1
#define mid (l+r)/2
using namespace std;
const int N=2e5+7;
int t,a[N],tree[4*N][3];
int n;
void init(int k,int l,int r){
    if(l>=r){
        tree[k][1]=a[l];
        tree[k][2]=a[l];
        return;
    }
    init(lch,l,mid);
    init(rch,mid+1,r);
    tree[k][1]=max(tree[lch][1],tree[rch][1]);
    tree[k][2]=min(tree[lch][2],tree[rch][2]);
}
 
int qryMax(int k,int l,int r,int ql,int qr){
    if(ql>qr){
        return 1e9+7;
    }
    if(ql<=l&&r<=qr){
        return tree[k][1];
    }
    int Max1=0,Max2=0;
    if(ql<=mid) Max1=qryMax(lch,l,mid,ql,qr);
    if(mid+1<=qr) Max2=qryMax(rch,mid+1,r,ql,qr);
    return max(Max1,Max2);
}
 
int qryMin(int k,int l,int r,int ql,int qr){
    if(ql>qr){
        return 1e9+7;
    }
    if(ql<=l&&r<=qr){
        return tree[k][2];
    }
    int Min1=1e9+7,Min2=1e9+7;
    if(ql<=mid) Min1=qryMin(lch,l,mid,ql,qr);
    if(mid+1<=qr) Min2=qryMin(rch,mid+1,r,ql,qr);
    return min(Min1,Min2);
 
}
 
 
 
bool judgeL(int ql,int qr,int key){
    int cnt=qryMin(1,1,n,ql,qr);
    if(cnt<=key){
        return true;
    }else{
        return false;
    }
}
bool judgeR(int ql,int qr,int key){
    int cnt=qryMin(1,1,n,ql,qr);
    if(cnt>=key){
        return true;
    }else{
        return false;
    }
}
int searchL(int ll,int rr,int key){
    int ql=ll,qr=rr;
    while(ql<=qr){
        int md=(ql+qr)/2;

        if(judgeL(ll,md,key)){
            qr=md-1;
        }else{
            ql=md+1;
        }
    }
    return ql;
}
 
int searchR(int ll,int rr,int key){
    int ql=ll,qr=rr;
    while(ql<=qr){
        int md=(ql+qr)/2;
        if(judgeR(ll,md,key)){
            ql=md+1;
        }else{
            qr=md-1;
        }
    }
    return qr;
}
bool judge(int ql,int qr,int key){
    int cnt=qryMax(1,1,n,ql,qr);
    if(cnt<=key){
        return true;
    }else{
        return false;
    }
}
int search(int ll,int rr,int key){
    int ql=ll,qr=rr;
    while(ql<=qr){
        int md=(ql+qr)/2;
        if(judge(md,n,key)){
            qr=md-1;
        }else{
            ql=md+1;
        }
    }
    return ql;
}
 
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int ok=0;
        init(1,1,n);
        for(int i=1;i<=n-2;i++){
            int key=qryMax(1,1,n,1,i);
            int sl=searchL(i+1,n,key);
            int sr=searchR(i+1,n,key);

            if(((sl<i+1||sl>n)||(sr<i+1||sr>n))&&qryMin(1,1,n,i+1,sl)!=key){
                continue;
            }else{
               
                if(sl+1>n) continue; 
                
                int z=search(sl+1,min(sr+1,n),key);
                
                if((z>=sl+1&&z<=min(sr+1,n))&&qryMax(1,1,n,z,n)==key){
                    ok=1;
                    printf("YES\n");
                    printf("%d %d %d\n",i,z-i-1,n-z+1);
                    break;
                }else{
                    continue;
                }
            }             
        }
        if(ok==0){
            printf("NO\n");
        }
    }
}

方法二:

#include <iostream>
#define lch 2*k
#define rch 2*k+1
#define mid (l+r)/2
using namespace std;
const int N=2e5+7;
int t,n,a[N],tree[4*N][3];
void init(int k,int l,int r){
    if(l>=r){
        tree[k][1]=a[l];
        tree[k][2]=a[l];
        return;
    }
    init(lch,l,mid);
    init(rch,mid+1,r);
    tree[k][1]=max(tree[lch][1],tree[rch][1]);
    tree[k][2]=min(tree[lch][2],tree[rch][2]);
}
 
int qryMax(int k,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tree[k][1];
    }
    int Max1=0,Max2=0;
    if(ql<=mid) Max1=qryMax(lch,l,mid,ql,qr);
    if(mid+1<=qr) Max2=qryMax(rch,mid+1,r,ql,qr);
    return max(Max1,Max2);
}
 
int qryMin(int k,int l,int r,int ql,int qr){
   //cout<<" "<<l<<" "<<r<<" "<<tree[k][2]<<endl;
    if(ql<=l&&r<=qr){
        return tree[k][2];
    }
    int Min1=1e9+7,Min2=1e9+7;
    if(ql<=mid) Min1=qryMin(lch,l,mid,ql,qr);
    if(mid+1<=qr) Min2=qryMin(rch,mid+1,r,ql,qr);
    return min(Min1,Min2);
}
 
int searchR(int k,int l,int r,int key){
    if(l>=r){
        return r;
    }
    int tem=tree[rch][1];
    int inx=-1;
    if(tem>=key){
        inx=searchR(rch,mid+1,r,key);
    }else{
        inx=searchR(lch,l,mid,key);  
    }
    return inx;
}
 
int searchL(int k,int l,int r,int key){
    if(l>=r){
        return r;
    }
    int tem=tree[rch][1];
    int inx=-1;
    if(tem>key){
        inx=searchL(rch,mid+1,r,key);
    }else{
        inx=searchL(lch,l,mid,key);  
    }
 
    return inx;
 
}
 
int search(int k,int l,int r,int key){
    if(l>=r){
 
        return r;
    }
    int tem=tree[rch][2];
    int inx=-1;
    if(tem<=key){
        inx=search(lch,l,mid,key);
    }else{
        inx=search(rch,mid+1,r,key);  
    }
 
    return inx;
 
}
 
int ikuzo(int k,int l,int r,int ql,int qr,int key){
    if(ql>qr){
        return 1e9+7;
    }
    if(ql<=l&&r<=qr){
        //cout<<"tree="<<tree[k][2]<<endl;
        if(tree[k][2]<=key) 
            return search(k,l,r,key);
        else 
            return 1e9+7;
    }
    int inx=1e9+7;
    if(ql<=mid) inx=min(inx,ikuzo(lch,l,mid,ql,qr,key));
    if(mid+1<=qr) inx=min(inx,ikuzo(rch,mid+1,r,ql,qr,key));
    return inx;
}
 
int main(){
 
    scanf("%d",&t);
 
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        init(1,1,n);
        int ok=1;
        for(int i=1;i<=n-2;i++){
            int key=qryMax(1,1,n,1,i);
            int jl=searchL(1,1,n,key);
            int jr=searchR(1,1,n,key);
 
            int ql=max(i+1,jl),qr=jr-1;
            if(ql>qr) continue;
            int inx;
            if(qryMin(1,1,n,i+1,ql)<=key){
                inx=ql;
            }else{
                inx=ikuzo(1,1,n,ql+1,qr,key);
            }
 
            if(inx!=1e9+7&&qryMin(1,1,n,i+1,inx)==key){
 
                printf("YES\n");
                printf("%d %d %d\n",i,inx-i,n-inx);
                ok=0;
                break;
            }
        }
        if(ok==1){
            printf("NO\n");
        }
    }
}
posted @ 2020-11-27 00:08  高级牛头人  阅读(110)  评论(2编辑  收藏  举报