zoukankan      html  css  js  c++  java
  • [线段树] Codeforces 1288E Messenger Simulator

    题目大意

    一个长度为 (n) 的好友列表,自上而下依次是 (1sim n),你依次收到了 (m) 条消息,第 (i) 条消息是 (a_i) 发来的,这时 (a_i) 会跳到会话列表的最上面,其它的按原顺序顺延,求 (1 sim n) 每个好友最靠上的位置和最靠下的位置。
    (1leq n,mleq 3 imes 10^5)

    题解

    首先考虑怎么去处理最靠上的位置。因为如果把一个好友移到最上面,那么除了他之外的所有人都会往下移,显然这对除了他之外的所有人的最靠上的位置是没有贡献的,直接把移动的这个人的最靠上的位置置为1即可。

    再考虑怎么去处理最靠下的位置。容易发现把一个人移动到最上面对其他人的最靠下的位置只增不减。所以我们只需要每次把 (x) 移动到最上面时询问一下 (x) 移动之前的位置,所有移动都完成后再询问下每个人当前的位置,然后对于每次移动之前询问的结果和所有移动都完成后的询问的结果取max即可。我们可以在 (n) 个位置前面加一排 (m) 个虚点,用0表示这 (n+m) 个位置上没有被占据的位置,用1表示被占据的位置,然后用线段树维护。记录下每个点当前的位置。把某个点移动到最前面只需移动到那些虚点上,询问该点当前的位置只需查询一次前缀和,即该点之前有多少个1即可。

    时间复杂度 (O((N+M)log(N+M)))

    这个建虚点的操作感觉有点巧妙,学习下。

    Code

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    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);
    }
    
    int SegTree[2400100];
    int AnsA[300010],AnsB[300010],Pos[300010];
    int N,M;
    
    void Build_SegTree(int Root,int L,int R){
        if(L==R){
            if(L>M) SegTree[Root]=1;
            return;
        }
        int mid=(L+R)>>1;
        Build_SegTree(Root<<1,L,mid);
        Build_SegTree(Root<<1|1,mid+1,R);
        SegTree[Root]=SegTree[Root<<1]+SegTree[Root<<1|1];
        return;
    }
    
    int Query(int Root,int L,int R,int QL,int QR){
        if(R<QL||QR<L) return 0;
        if(QL<=L && R<=QR) return SegTree[Root];
        int mid=(L+R)>>1;
        return Query(Root<<1,L,mid,QL,QR)+Query(Root<<1|1,mid+1,R,QL,QR);
    }
    
    void Update(int Root,int L,int R,int pos,int Add){
        if(L==R){SegTree[Root]+=Add;return;}
        int mid=(L+R)>>1;
        if(pos<=mid) Update(Root<<1,L,mid,pos,Add);
        else Update(Root<<1|1,mid+1,R,pos,Add);
        SegTree[Root]=SegTree[Root<<1]+SegTree[Root<<1|1];
        return;
    }
    
    int main(){
        Read(N);Read(M);
        Build_SegTree(1,1,N+M);
        for(RG i=1;i<=N;++i){
            AnsA[i]=AnsB[i]=i;
            Pos[i]=M+i;
        }
        for(RG i=1;i<=M;++i){
            int x;Read(x);AnsA[x]=1;
            AnsB[x]=max(AnsB[x],Query(1,1,N+M,1,Pos[x]));
            Update(1,1,N+M,Pos[x],-1);
            Update(1,1,N+M,M-i+1,1);
            Pos[x]=M-i+1;
        }
        for(RG i=1;i<=N;++i){
            AnsB[i]=max(AnsB[i],Query(1,1,N+M,1,Pos[i]));
            printf("%d %d
    ",AnsA[i],AnsB[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    关于JDK中自带的类加载器
    关于Spring框架
    关于Java JUC
    数据库-数据添加与删除-视图-索引-存储过程
    数据库-查询练习
    数据库-数据类型-数据库创建表的 约束以及 DDL操作
    数据库-多表连接查询
    数据库笔记整理-数据库概述-三大范式及数据库基本命令
    JAVA笔记整理-JAVA网络编程-TCP/UDP传输
    JAVA笔记整理-线程二
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12635489.html
Copyright © 2011-2022 走看看