[贪心][线段树] Codeforces 1348F Phoenix and Memory

题解

首先我们得找到任意一个合法的序列,这可以使用贪心算法在 \(O(N\log N)\) 的时间复杂度内做到。我们可以把所有的区间 \((a_i,b_i)\) 按左端点从小到大进行排序,然后从左到右扫描这些区间。我们去找朋友 \(j\) 可以在哪些位置,我们把所有左端点 \(a_i\leq j\) 的区间的右端点 \(b_i\) 加入一个 multiset,然后令朋友 \(j\) 在有着最小的右端点 \(b_i\) 的那个位置 \(i\),然后把 \(b_i\) 在 multiset中移除。

现在我们已经得到了1个合法的序列,我们只需要通过交换已找到的合法序列中两个朋友的位置就可以得到另一个合法的序列。

\(p_i\) 表示朋友 \(i\) 在任意一个序列中的位置。如果存在一个朋友 \(i\),并且存在一个朋友 \(j\),满足 \(a_{p_j}\leq i<j\leq b_{p_i}\),这时,我们就可以交换朋友 \(i,j\) 的位置得到另一个合法的序列,这个可以用线段树来解决。时间复杂度 \(O(N\log N)\)

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <map>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

multiset<pair<int,int> > S;
struct Node{int a,b,ID;};
struct SegTreeNode{int val,ID;};
Node Data[200010];
int Pos[200010],List[200010],a[200010],b[200010];
SegTreeNode SegTree[800010];
int N;

bool cmp(Node A,Node B){return A.a<B.a;}

void Build_SegTree(int Root,int L,int R){
    if(L==R){
        SegTree[Root].val=a[Pos[L]];
        SegTree[Root].ID=L;
        return;
    }
    int mid=(L+R)>>1;
    Build_SegTree(Root<<1,L,mid);
    Build_SegTree(Root<<1|1,mid+1,R);
    int ls=SegTree[Root<<1].ID,rs=SegTree[Root<<1|1].ID;
    if(SegTree[Root<<1].val<SegTree[Root<<1|1].val){
        SegTree[Root].val=SegTree[Root<<1].val;
        SegTree[Root].ID=ls;
    }
    else{
        SegTree[Root].val=SegTree[Root<<1|1].val;
        SegTree[Root].ID=rs;
    }
    return;
}

pair<int,int> Query(int Root,int L,int R,int QL,int QR){
    if(R<QL || QR<L) return make_pair(2147483647,0);
    if(QL<=L && R<=QR) return make_pair(SegTree[Root].val,SegTree[Root].ID);
    int mid=(L+R)>>1;
    auto ls=Query(Root<<1,L,mid,QL,QR);
    auto rs=Query(Root<<1|1,mid+1,R,QL,QR);
    if(ls.first<rs.first) return ls;
    return rs;
}

int main(){
    Read(N);
    for(RG i=1;i<=N;++i){
        Read(Data[i].a);
        Read(Data[i].b);
        a[i]=Data[i].a;b[i]=Data[i].b;
        Data[i].ID=i;
    }
    a[0]=2147483647;
    sort(Data+1,Data+N+1,cmp);
    int p=0;
    for(RG i=1;i<=N;++i){
        while(p+1<=N && Data[p+1].a<=i){
            ++p;S.insert(make_pair(Data[p].b,Data[p].ID));
        }
        Pos[i]=S.begin()->second;
        S.erase(S.begin());
    }
    for(RG i=1;i<=N;++i)
        List[Pos[i]]=i;
    Build_SegTree(1,1,N);
    bool flag=false;
    int u,v;
    for(RG i=1;i<=N;++i){
        if(i+1>b[Pos[i]]) continue;
        auto tmp=Query(1,1,N,i+1,b[Pos[i]]);
        if(tmp.first<=i){
            flag=true;
            u=Pos[tmp.second],v=Pos[i];
            break;
        }
    }
    if(!flag){
        printf("YES\n");
        for(RG i=1;i<=N;++i)
            printf("%d ",List[i]);
        printf("\n");
        return 0;
    }
    printf("NO\n");
    for(RG i=1;i<=N;++i)
        printf("%d ",List[i]);
    printf("\n");
    swap(List[u],List[v]);
    for(RG i=1;i<=N;++i)
        printf("%d ",List[i]);
    printf("\n");
    return 0;
}
posted @ 2020-05-02 23:25  AE酱  阅读(458)  评论(1编辑  收藏  举报