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

Posted aemshana

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[贪心][线段树] Codeforces 1348F Phoenix and Memory相关的知识,希望对你有一定的参考价值。

题解

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

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

(p_i) 表示朋友 (i) 在任意一个序列中的位置。如果存在一个朋友 (i),并且存在一个朋友 (j),满足 (a_{p_j}leq i<jleq b_{p_i}),这时,我们就可以交换朋友 (i,j) 的位置得到另一个合法的序列,这个可以用线段树来解决。时间复杂度 (O(Nlog 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
");
        for(RG i=1;i<=N;++i)
            printf("%d ",List[i]);
        printf("
");
        return 0;
    }
    printf("NO
");
    for(RG i=1;i<=N;++i)
        printf("%d ",List[i]);
    printf("
");
    swap(List[u],List[v]);
    for(RG i=1;i<=N;++i)
        printf("%d ",List[i]);
    printf("
");
    return 0;
}

以上是关于[贪心][线段树] Codeforces 1348F Phoenix and Memory的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces1099F. Cookies(线段树+dp+贪心+博弈)

CodeForces - 1529E Trees of Tranquillity(贪心+线段树)

Codeforces Round #401 (Div. 2) E 贪心,线段树

[比赛] Codeforces Round #538 (Div. 2) solution (贪心,数学其他,二分,线段树)

Codeforces Round #638 (Div. 2) F. Phoenix and Memory 区间贪心+线段树

Codeforces1099F. CookiesDP线段树贪心博弈沙比提(这是啥算法)