CodeForces 1288 E.Messenger Simulator (树状数组)

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

Input

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

题意:

给n,m次操作
起初为1,2,3...n的序列
每次操作给一个数x
把x移动第一位
问m次操作过程后
每个数到过的最左边和最右边的位置

例如给n=3,m=2,初始序列1,2,3
第一次操作x=2,序列变为2,1,3
第二次操作x=3,序列变为3,2,1 
又上可知结果为:
l1=1,r1=3
l2=1,r2=2
l3=1,r3=3

思路:

显然m次操作出现过的数lx肯定为1

初始状态:li=i,ri=i
给n和m,在n个数前面开m个空位
例如n=3,m=2
则序列为0,0,1,2,3
1.第一次操作x=2,2移到前面最后一个0,序列变为0,2,1,0,3
更新l2=1,然后求出2前面又多少个数pre=0,所以r2=max(r2,pre+1)=2
2.第二次操作x=3,2移到前面最后一个0,序列变为3,2,1,0,0
更新l3=1,然后求出3前面又多少个数pre=0,所以r3=max(r3,pre+1)=3

最后对于每个数在扫一遍,更新前面有多少个数,
这里发现pre1=2,则r1=max(r1,pre1+1)=3
所有数据更新完毕,输出即可

数字的移动和求数字前面有多少个数,用权值线段树或者树状数组都行

总结:
这个方法很好的解决了每次操作理论上x前面所有数要向后移动一格的问题

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=6e5+5;//因为前面要空出m个,所以数组开两倍大小
int l[maxm],r[maxm];
int c[maxm];
int pos[maxm];
int n,m;
int lowbit(int i){
    return i&-i;
}
void add(int i,int t){
    while(i<maxm){
        c[i]+=t;
        i+=lowbit(i);
    }
}
int ask(int i){
    int ans=0;
    while(i){
        ans+=c[i];
        i-=lowbit(i);
    }
    return ans;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){//init
        l[i]=r[i]=i;
        add(i+m,1);
        pos[i]=i+m;
    }
    int last=m;
    while(m--){
        int x;
        cin>>x;
        l[x]=1;
        int num=ask(pos[x]);//前面有多少个数
        r[x]=max(r[x],num);
        if(num==1)continue;//如果是第一直接跳过
        add(pos[x],-1);//移走
        pos[x]=last;
        add(pos[x],1);//移到新位置
        last--;
    }
    for(int i=1;i<=n;i++){//最后在扫一遍更新r[i]
        r[i]=max(r[i],ask(pos[i]));
    }
    for(int i=1;i<=n;i++){
        cout<<l[i]<<' '<<r[i]<<endl;
    }
    return 0;
}
发布了364 篇原创文章 · 获赞 26 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/104009340