Messenger Simulator(逆序+树状数组)

Polycarp is a frequent user of the very popular messenger. He’s chatting with his friends all the time. He has nn friends, numbered from 11 to nn.

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

So his recent chat list can be represented with a permutation pp of size nn. p1p1 is the most recent friend Polycarp talked to, p2p2 is the second most recent and so on.

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

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

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

if he gets messaged by friend 33, then pp becomes [3,4,1,5,2][3,4,1,5,2];
if he gets messaged by friend 44, then pp doesn’t change [4,1,5,3,2][4,1,5,3,2];
if he gets messaged by friend 22, then pp becomes [2,4,1,5,3][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 nn and mm (1≤n,m≤3⋅1051≤n,m≤3⋅105) — the number of Polycarp’s friends and the number of received messages, respectively.

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

Output
Print nn 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
Note
In the first example, Polycarp’s recent chat list looks like this:

扫描二维码关注公众号,回复: 9082245 查看本文章

[1,2,3,4,5][1,2,3,4,5]
[3,1,2,4,5][3,1,2,4,5]
[5,3,1,2,4][5,3,1,2,4]
[1,5,3,2,4][1,5,3,2,4]
[4,1,5,3,2][4,1,5,3,2]
So, for example, the positions of the friend 22 are 2,3,4,4,52,3,4,4,5, respectively. Out of these 22 is the minimum one and 55 is the maximum one. Thus, the answer for the friend 22 is a pair (2,5)(2,5).

In the second example, Polycarp’s recent chat list looks like this:

[1,2,3,4][1,2,3,4]
[1,2,3,4][1,2,3,4]
[2,1,3,4][2,1,3,4]
[4,2,1,3][4,2,1,3]
思路:本题的难点就在于如何实现这个元素的变动。链表对于查询的效率特别差,所以不行。STL中也没有太适合的工具。那就要考虑一下有没有合适的数据结构了。
用树状数组来处理这个问题,对于新联系的人来说,我们就把这个数原来的位置更新为0,把现在的位置更新为1。貌似可以,但是单纯的用树状数组的话,如果新联系一个人,那么这个位置后面的数字也都要动,否则这些数字之间的关系就会出错。如果我们把数组中的数字倒过来,新联系一个人,那么就将它加入到后面,就解决这个问题了。
例如样例:
5 4
3 5 1 4
事先是1 2 3 4 5,倒过来之后就是5 4 3 2 1,利用树状数组更新后的就是1 1 1 1 1,新联系了3,那么就变成了5 4 2 1 3,更新树状数组后就是1 1 0 1 1 1。诸如此类,一直下去。
对于在联系列表中的数字来说,最小位置肯定是1。对于不在联系列表中的数字来说,最小位置就是初始的位置。对于最大位置,我们用树状数组不断的更新。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=6e5+100;
int a[maxx];
int pos[maxx];
int c[maxx];
int _min[maxx],_max[maxx];
int n,m;
inline int lowbit(int x)
{
	return x&-x;
}
inline void update(int x,int v)
{
	while(x<=maxx)
	{
		c[x]+=v;
		x+=lowbit(x);
	}
}
inline int query(int u)
{
	int ans=0;
	while(u>0)
	{
		ans+=c[u];
		u-=lowbit(u);
	}
	return ans;
}
int main()
{
	while(cin>>n>>m)
	{
		memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++)
		{
			pos[i]=n-i+1;//pos数组记录数字的位置
			update(pos[i],1);
			_min[i]=_max[i]=i;
		}
		int x;
		for(int i=n+1;i<=n+m;i++)
		{
			scanf("%d",&x);
			_min[x]=1;
			_max[x]=max(_max[x],query(maxx)-query(pos[x]-1));//更新最大值数组
			update(pos[x],-1);//将之前的位置更新为0
			pos[x]=i;
			update(pos[x],1);//现在的位置更新为1。
		}
		for(int i=1;i<=n;i++) _max[i]=max(_max[i],query(maxx)-query(pos[i]-1));//对于那些没有出现在联系列表中的,就要再更新一遍。
		for(int i=1;i<=n;i++) cout<<_min[i]<<" "<<_max[i]<<endl;
	}
}

努力加油a啊,(o)/~

发布了414 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/starlet_kiss/article/details/104135984