cf1288e Messenger Simulator

传送门

类似于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
", l[i], r[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/Emcikem/p/14119752.html