• [贪心][线段树] 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;
    }
    
  • 相关阅读:
    前端之JQuery:JQuery文档操作
    前端之JQuery:JQuery属性操作
    前端之JQuery:JQuery基本语法
    前端之JavaScript:JS之DOM对象三
    前端之JavaScript:JS之DOM对象二
    初始django
    mysql 索引
    多表查询
    单表查询
    外键的三种形式
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12820216.html
Copyright © 2020-2023  润新知