CodeForces - 802B Heidi and Library (medium)

Whereas humans nowadays read fewer and fewer books on paper, book readership among marmots has surged. Heidi has expanded the library and is now serving longer request sequences.

Input

Same as the easy version, but the limits have changed: 1 ≤ n, k ≤ 400 000.

Output

Same as the easy version.

Example

Input
4 100
1 2 2 1
Output
2
Input
4 1
1 2 2 1
Output
3
Input
4 2
1 2 3 1
Output
3

题目大意:
有n条用户需要的书,图书馆最多只能有k本书,如果用户需要第i本书,图书馆没有第i本书,那么就需要购买第i本书,如果这时候图书馆的书多于k本,
那么需要扔掉一本书,以保持图书数量在k本以内,一开始图书馆一本书也没有,问最少需要购买多少次书,以满足所有需求。
分析:
贪心,当需要扔书时,优先扔后面已经不需要的书,当后面没有不需要的书的时候,优先扔需要被用到的时间最晚的书。
比如:
6 2
1 2 3 4 2 1
就是先买1 2两本书,买第三本书3时优先扔1,因为1用到的时候最晚,总不能这一次扔了2,马上就要把2买回来。。。。。。
然后买4的时候扔3,因为后面3已经不需要再被用到了,然后2已经有了不用再买了,之后再买一次1,(4和2随便扔一本)就结束了。
总共需要购买5次
实现方法:
用优先队列去实现,取下一次每本书第一次出现的时间中最晚的哪一本,如果这本书已经不需要再买,设置其值为INF,即出现的时间无限晚。
一本书的指针值更新之后,优先队列中某些元素就会失效,所以元素出队的时候要比较一下,队列出去的元素是否和储存的值相同,如果不同,
弃掉重取,直至有用为止。
代码:
#include<iostream>
using namespace std;
#include<queue>
#include<cstdio>
#include<map>
#include<queue>
#include<vector>
int cs = 0;
typedef long long LL;
int n, k;
int fs[4001000];//记录下一次出现的时间
struct data
{
    int sj;
    int bh;
    bool operator<(const data &b)const
    {
        return this->sj<b.sj;
    }
};
int a[500000];
bool v[500000];
vector<int> ne[500000];//记录每本书依次出现的时间
int zz[500000];//一个指向每本书出现的次数的指针
priority_queue<struct data> team;
int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        ne[a[i]].push_back(i);
        fs[a[i]] = i;
    }
    int ans = 0;
    cs = 0;
    for (int i = 1; i <= n; i++)
    {
        //如果存在更新其队列中的值
        if (v[a[i]]) {
            struct data pd;
            pd.bh = a[i];
            zz[a[i]]++;
            if (zz[a[i]] + 1>ne[a[i]].size()) fs[a[i]] = 0x7fffffff;
            else
                fs[a[i]] = ne[a[i]][zz[a[i]]];
            pd.sj = fs[a[i]];
            team.push(pd);
            continue;
        }
        ans += 1;
        cs += 1;
        v[a[i]] = 1;
        if (cs>k) {
                        /*取队列中,与记录出现时间相符的有效值,扔掉时间不相同的无用值*/
            struct data pt = team.top();
            while (pt.sj != fs[pt.bh])
            {
                team.pop();
                if (team.empty()) break;
                pt = team.top();
            }
            team.pop();
            v[pt.bh] = 0;
        }
                //买一本新书后更新其值
        struct data pd;
        pd.bh = a[i];
        zz[a[i]]++;
                //zz指针大于这种书出现过的次数,即这本书不会再出现
        if (zz[a[i]] + 1>ne[a[i]].size()) fs[a[i]] = 0x7fffffff;
        else
            fs[a[i]] = ne[a[i]][zz[a[i]]];
        pd.sj = fs[a[i]];
        team.push(pd);
    }
    cout << ans << endl;
    return 0;
}
    

 

posted @ 2017-08-02 19:26  晓风微微  阅读(280)  评论(0编辑  收藏  举报