Codeforce 1288 E. Messenger Simulator (思維+樹狀數組)

題目鏈接:https://codeforces.com/contest/1288/problem/E

題目大意:

給定一個1到n的排列,現在有m個操作,每個操作給定一個數x,表示將x移動到排列的第一個,其他位置相對不變,問你每個數,他的位置的最大值和最小值分別是多少?

思路:

思路應該是模擬操作,並且用數據結構加速操作,如何操作更快呢?

因爲每次我只移動一個數,其他的數相對位置不會改變,所以考慮將數組擴大一倍。

比如,原數組爲1 2 3 4 5,m={3,5,1,4}

我們將它倒過來(爲什麼倒過來呢?因爲這樣你移動的數都在數組後面了,便於操作),並且在後面加上m個空位,如下

5 4 3 2 1 __ __ __ __

現在將3移動到第一個,也就是數組的最後一個,如下

5 4 __ 2 1 3 __ __ __

這樣的話,3的最小值一定是1(因爲他被操作了,一定會移動到第一位),最大值怎麼算呢?直接用樹狀數組查詢[pos[3],n]這個範圍內有多少個數就可以了。

然後我們更新pos[3],並將之前pos[3]的3刪除掉,這些操作樹狀數組都可以做。

這樣一直模擬m次操作之後,再對每個數更新一遍最大值(和之前一樣,直接查詢最後[pos[3],n]這個範圍內有多少個數就可以了。

問題:

爲什麼不需要每次對每個數最大值的更新呢?比如我做完一個操作,不應該是每個數的最大值都更新了嗎?

回答:

因爲對於這一輪沒有被操作到的數,他的位置一定會往後移動,也就是說對於一個數x,如果他沒有被操作到,他的最大值maxx[x]一定是不斷變大的,所以我們可以等到操作到了x再更新最大值,或者等到最後全體大更新再更新也行。

還有什麼問題也歡迎提出來。

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

const int maxn=6e5+10;
int pos[maxn];
int c[maxn];
int lowbit(int x){
    return x&-x;
}
int n,m;
void add(int x,int v){
    while(x<maxn){
        c[x]+=v;
        x+=lowbit(x);
    }
}
int query(int x){
    int res=0;
    while(x>0){
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
int maxx[maxn],minn[maxn];
signed main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        pos[i]=i;
        maxx[i]=minn[i]=i;
    }
    reverse(pos+1,pos+n+1);
    for(int i=1;i<=n;i++){
        add(pos[i],1);
    }
    for(int i=1;i<=m;i++){
        int x;
        scanf("%d",&x);
        minn[x]=1;
        maxx[x]=max(maxx[x],query(maxn-1)-query(pos[x]-1));
        add(pos[x],-1);
        pos[x]=i+n;
        add(pos[x],1);
    }
    for(int i=1;i<=n;i++){
        maxx[i]=max(maxx[i],query(maxn-1)-query(pos[i]-1));
    }
    for(int i=1;i<=n;i++){
        printf("%d %d\n",minn[i],maxx[i]);
    }
    return 0;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章