CF-E. Messenger Simulator

CF-E. Messenger Simulator
Polycarp is a frequent user of the very popular messenger. He’s chatting with his friends all the time. He has n friends, numbered from 1 to n.

Recall that a permutation of size n is an array of size n such that each integer from 1 to n occurs exactly once in this array.

So his recent chat list can be represented with a permutation p of size n. p1 is the most recent friend Polycarp talked to, p2 is the second most recent and so on.

Initially, Polycarp’s recent chat list p looks like 1,2,…,n (in other words, it is an identity permutation).

After that he receives m messages, the j-th message comes from the friend aj. And that causes friend aj to move to the first position in a permutation, shifting everyone between the first position and the current position of aj by 1. Note that if the friend aj is in the first position already then nothing happens.

For example, let the recent chat list be p=[4,1,5,3,2]:

if he gets messaged by friend 3, then p becomes [3,4,1,5,2];
if he gets messaged by friend 4, then p doesn’t change [4,1,5,3,2];
if he gets messaged by friend 2, then p becomes [2,4,1,5,3].
For each friend consider all position he has been at in the beginning and after receiving each message. Polycarp wants to know what were the minimum and the maximum positions.

Input
The first line contains two integers n and m (1≤n,m≤3⋅105) — the number of Polycarp’s friends and the number of received messages, respectively.

The second line contains m integers a1,a2,…,am (1≤ai≤n) — the descriptions of the received messages.

Output
Print n pairs of integers. For each friend output the minimum and the maximum positions he has been in the beginning and after receiving each message.

Examples

5 4
3 5 1 4

output

1 3
2 5
1 4
1 5
1 5

input

4 3
1 2 4

output

1 3
1 2
3 4
1 4

发现如果i有消息,i的最小位置是1,否则就是原来的位置。
i的最大位置可能是i的消息来的时候,也可能是全部消息都发完了之后。
所以,用splay模拟整个游戏,如果x放到最前面,则只更新x的最大位置即可,因为不是x的最大位置在消息x之后只可能会变大,不会变小。
复杂度 O ( m l o g n + n l o g n ) O(mlogn+nlogn) O(mlogn+nlogn)

#include<bits/stdc++.h>
using namespace std;
char buf[1<<20],*_=buf,*__=buf;
#define gc() (_==__&&(__=(_=buf)+fread(buf,1,1<<20,stdin),_==__)?EOF:*_++)
#define TT template<class T>inline
TT bool read(T &x){
    x=0;char c=gc();bool f=0;
    while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
    while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
    if(f)x=-x;return 1;
}
TT bool read(T&a,T&b){return read(a)&&read(b);}
TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
typedef long long ll;
const ll MAXN=3e5+8,mod=1e9+7,inf=0x3f3f3f3f;
int mp[MAXN],n,m,x;;
struct Splay{
    int val[MAXN],num[MAXN],ls[MAXN],rs[MAXN],fa[MAXN];
    int a[MAXN],b[MAXN];
    inline void up(int x){
        num[x]=1;
        if(ls[x])num[x]+=num[ls[x]];
        if(rs[x])num[x]+=num[rs[x]];
    }
    int cnt,root;
    inline int build(int l,int r,int f){
        int mid=(l+r)>>1,id=++cnt;
        num[id]=1,fa[id]=f,val[id]=mid,a[id]=mid,b[id]=mid;
        mp[mid]=id;
        if(l==r){ls[id]=rs[cnt]=0;return id;}
        if(l<mid)ls[id]=build(l,mid-1,id);
        if(r>mid)rs[id]=build(mid+1,r,id);
        return up(id),id;
    }
    inline bool islson(int x){return ls[fa[x]]==x?1:0;}
    inline void rotate(int x){
        int f=fa[x],ff=fa[f];
        if(islson(x))ls[f]=rs[x],fa[rs[x]]=f,rs[x]=f,fa[f]=x;
        else         rs[f]=ls[x],fa[ls[x]]=f,ls[x]=f,fa[f]=x;
        fa[x]=ff;
        if(ls[ff]==f)ls[ff]=x;
        else rs[ff]=x;
        up(f);
    }
    void splay(int x,int pos){
        for(int f,ff;f=fa[x],ff=fa[f],f^pos;rotate(x))if(ff^pos){
            if(islson(x)^islson(f))rotate(x);
            else rotate(f);
        }up(x);
        if(!pos)root=x;
    }
    int getpre(){
        int x=ls[root];
        if(!x)return 0;
        while(rs[x])x=rs[x];
        return x;
    }
    void proc(int k){//将k位置的消息移动至最前面
        a[k]=1;
        splay(k,0);
        if(ls[k])b[k]=max(b[k],num[ls[k]]+1);
        int x=root,y=ls[root],z=getpre(),R=rs[root];
        if(!y)return;
        root=y,fa[y]=0,ls[x]=0;
        rs[z]=R,fa[R]=z,rs[x]=0;
        if(R)splay(R,0);
        y=root;
        while(ls[y])y=ls[y];
        ls[y]=x,fa[x]=y;
        splay(x,0);
    }
    void Print(){
        for(int i=1;i<=n;++i){
            splay(mp[i],0);//此时还要再更新一次
            if(ls[root])b[root]=max(b[root],num[ls[root]]+1);
            printf("%d %d\n",a[root],b[root]);
        }
    }
}t;
int main() {
    read(n,m);
    t.root =t.build(1,n,0);
    while(m--)read(x),t.proc(mp[x]);
    t.Print();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值