类似于qq的,有人给你发消息,那么他就会变成第一个。最后让你求每个人的最小排名和最大排名
首先,对于发过消息的人,最小排名是1,没有发过消息的,最小排名就是他的初始位置\(i\)
对于没有发过消息的,那么他的最大排名就是看所有发过消息的人里面,有多少个人编号大于自己,那么自己就往后多少名
对于发过消息的人,有两种情况,第一种情况就是第一次发消息前有多少人编号大于自己,然后自己就往后移多少名,或者说在两次发消息的间隔里,查看有多少人发了消息,每次就是人数 + 1,但注意的是最后一次发消息后排名还是会变的,所以还要注意查看最后一次发消息到发消息结束的区间。
那么问题转换为在线查询一个区间有多少个数字比我大
以及离散查询一个区间出现了多少种数字
树状数组维护一下就行了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
struct BIT{
int c[N];
void init(){memset(c, 0, sizeof(c));}
int lowbit(int x){
return x & (-x);
}
void add(int k, int x){
for(; k < N; k += lowbit(k)) c[k] += x;
}
int ask(int x){
ll ans = 0;
for(; x; x -= lowbit(x)) ans += c[x];
return ans;
}
} b;
struct Query{
int l, r, id;
bool operator < (const Query &b) const {
return r < b.r;
}
} q[N];
int a[N], l[N], r[N], vis[N], last[N], tot;
int main(){
int n, m; scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) l[i] = r[i] = i;
for(int i = 1; i <= m; i++) {
scanf("%d", &a[i]);
l[a[i]] = 1;
int now = b.ask(a[i]) - b.ask(a[i] - 1);
if(now == 0) {
b.add(a[i], 1);
}
if(!vis[a[i]]) {
r[a[i]] = max(r[a[i]], a[i] + b.ask(n) - b.ask(a[i]));
vis[a[i]] = 1;
last[a[i]] = i;
} else {
q[++tot].l = last[a[i]] + 1;
q[tot].r = i - 1;
q[tot].id = a[i];
last[a[i]] = i;
}
}
for(int i = 1; i <= n; i++) {
if(vis[i]) continue;
r[i] = max(r[i], b.ask(n) - b.ask(i) + i);
}
for(int i = 1; i <= n; i++) {
if(!vis[i]) continue;
q[++tot].l = last[i] + 1;
q[tot].r = m;
q[tot].id = i;
}
sort(q + 1, q + tot + 1);
memset(vis, 0, sizeof(vis)); b.init();
int next = 1;
for(int i = 1; i <= tot; i++) {
for(int j = next; j <= q[i].r; j++) {
if(vis[a[j]]) b.add(vis[a[j]], -1);
b.add(j, 1);
vis[a[j]] = j;
}
next = q[i].r + 1;
r[q[i].id] = max(r[q[i].id], b.ask(q[i].r) - b.ask(q[i].l - 1) + 1);
}
for(int i = 1; i <= n; i++)
printf("%d %d\n", l[i], r[i]);
return 0;
}