Optimal Subsequences(Hard Version)(二分套线段树+离线处理)

题目链接:

题解思路:首先按数组中的下标建一棵线段树,假设原数组是a,我们用一个新数组b记录a,将b数组先按权值排序、再按下标排序,然后再用数组记录m次询问,按k从小到大排序,再对每个询问二分线段树右边界,最后把m次询问按原来的顺序排回来,最后按顺序输出答案即可。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
const int MAXN = 2e5+10;
const double EPS = 1e-12;

int T,n,m;
int sum[MAXN<<2];
struct A{
    int x,pos;
}a[MAXN],b[MAXN];
struct node{
    int k,pp,id,ans;
}q[MAXN];

inline void Update(int l,int r,int rt,int pos){
    if(pos==l&&l==r){
        sum[rt]=1;
        return ;
    }
    int mid=(l+r)/2;
    if(pos<=mid)Update(ls,pos);
    else Update(rs,pos);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

inline int Query(int l,int r,int rt,int pos){
    if(pos>=r)return sum[rt];
    int mid=(l+r)/2;
    int ans=0;
    ans+=Query(ls,pos);
    if(pos>mid)ans+=Query(rs,pos);
    return ans;
}

bool cmp1(A aa,A bb){
    if(aa.x!=bb.x)return aa.x>bb.x;
    else return aa.pos<bb.pos;
}

bool cmp2(node aa,node bb){
    return aa.k<bb.k;
}

bool cmp3(node aa,node bb){
    return aa.id<bb.id;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i].pos=i;
        b[i]=a[i];
    }
    sort(b+1,b+n+1,cmp1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d",&q[i].k,&q[i].pp);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp2);
    int now=1;
    for(int i=1;i<=m;i++){
        for(int j=now;j<=q[i].k;j++)Update(1,n,1,b[j].pos);
        now=q[i].k+1;
        int l=1,r=n,k;
        while(l<=r){
            int mid=(l+r)/2;
            if(Query(1,n,1,mid)<q[i].pp)l=mid+1;
            else {
                r=mid-1;
                k=mid;
            }
        }
        q[i].ans=a[k].x;
    }
    sort(q+1,q+m+1,cmp3);
    for(int i=1;i<=m;i++)printf("%d
",q[i].ans);
}

悄悄说一句,其实没必要二分,二分的log完全可以去掉...

这里放一份去掉二分的代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
const int MAXN = 2e5+10;
const double EPS = 1e-12;

int T,n,m;
int sum[MAXN<<2];
struct A{
    int x,pos;
}a[MAXN],b[MAXN];
struct node{
    int k,pp,id,ans;
}q[MAXN];

inline void Update(int l,int r,int rt,int pos){
    if(pos==l&&l==r){
        sum[rt]=1;
        return ;
    }
    int mid=(l+r)/2;
    if(pos<=mid)Update(ls,pos);
    else Update(rs,pos);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

inline int Query(int l,int r,int rt,int k){
    if(l==r)return a[l].x;
    int mid=(l+r)/2;
    if(sum[rt<<1]>=k)return Query(ls,k);
    else return Query(rs,k-sum[rt<<1]);
}

bool cmp1(A aa,A bb){
    if(aa.x!=bb.x)return aa.x>bb.x;
    else return aa.pos<bb.pos;
}
bool cmp2(node aa,node bb){ return aa.k<bb.k; }
bool cmp3(node aa,node bb){ return aa.id<bb.id; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i].x); a[i].pos=i; b[i]=a[i]; } sort(b+1,b+n+1,cmp1); scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d %d",&q[i].k,&q[i].pp); q[i].id=i; } sort(q+1,q+m+1,cmp2); int now=0; for(int i=1;i<=m;i++){ while(now<q[i].k)Update(1,n,1,b[++now].pos); q[i].ans=Query(1,n,1,q[i].pp); } sort(q+1,q+m+1,cmp3); for(int i=1;i<=m;i++)printf("%d ",q[i].ans); }
原文地址:https://www.cnblogs.com/Mmasker/p/11927495.html