• [贪心][线段树] 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;
    }
    
  • 相关阅读:
    客户端回调 Watcher ?
    Container 在微服务中的用途是什么?
    什么是持续集成(CI)?
    Zookeeper 的典型应用场景 ?
    Java 中 Semaphore 是什么?
    elasticsearch 了解多少,说说你们公司 es 的集群架构,索 引数据大小,分片有多少,以及一些调优手段 。
    Dubbo 用到哪些设计模式?
    简述 Memcached 内存管理机制原理?
    ACL 权限控制机制 ?
    一般使用什么注册中心?还有别的选择吗?
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12820216.html
Copyright © 2020-2023  润新知