[线段树] Codeforces 1288E Messenger Simulator

题目大意

一个长度为 \(n\) 的好友列表,自上而下依次是 \(1\sim n\),你依次收到了 \(m\) 条消息,第 \(i\) 条消息是 \(a_i\) 发来的,这时 \(a_i\) 会跳到会话列表的最上面,其它的按原顺序顺延,求 \(1 \sim n\) 每个好友最靠上的位置和最靠下的位置。
\(1\leq n,m\leq 3\times 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\n",AnsA[i],AnsB[i]);
    }
    return 0;
}
posted @ 2020-04-05 00:32  AE酱  阅读(117)  评论(0编辑  收藏  举报