题目。。很长。。我一开始还没有理解。。语文果然有待加强的节奏啊~
思路大概如下:
n是10000,m是1000000,但是pi会有1e9,那么就是需要离散化的节奏。
用一个数据结构
struct wyh1
{
int p , pnum;
bool operator < (const wyh1 & x) const
{
if(pnum != x.pnum) return pnum < x.pnum;
return p < x.p;
}
}w[M];
p是编号,也就是处于询问中的第几个,pnum就是这个询问访问的页面编号。
重载小于符号,根据pnum的大小排序,如果pnum相同的话根据p来
然后调用sort函数。再弄一个数组a,a[i]代表编号为i的询问离散化后的值。
再维护一个at,at[num]表示离散化后为num值的页面是否在实际内存空间中存储。
维护一个times数组,代表临时访问某个页面的次数。
然后用一个堆维护当前最少访问次数并且进入最早的页面是哪一个。
struct wyh
{
int ti , num , t;
bool operator < (const wyh & x) const
{
if(ti != x.ti) return ti > x.ti;
return t > x.t;
}
};
ti代表这个页面的访问次数,num。。。可以无视。。t代表加入时间。
priority_queue <wyh> q; 声明一个堆
还得考虑的一个问题就是如何更新堆中维护的那些页面的访问次数,首先就是暴力,暴力的一个个拉出来更新再加入,虽然慢但是还是可以过的,因为时间限制是5秒一个。
但是愚蠢的我写完这个之后还去想了一个用全局访问次数来维护,但是这样是不可以的,因为堆不支持这样,你更新的是全局,但是不会更新堆里的数据。
亏我还因此纠结了好久,果然还是太弱了,哎。。
具体怎么写呢?
O(m)先扫一遍吧,获取到a[i]的值,然后判断at[a[i]]是否为1,为1 的话自然就是在实际内存中,那么就查询成功了,ans + 1,然后还得更新一下 times[a[i]]的内容,这个
times我为什么叫临时的呢?因为你一个堆,不可能时时刻刻都去更改里面的内容,所以用一个times数组存到全局里面,到时候一次性更新上去就可以了。
如果说at[a[i]]不为1,首先就判断堆中元素的个数如果小于n说明有空页面,直接插入到堆里面就可以了,关键是对于等于n的情况。
现在我们不能够单纯的用堆顶的元素去替换对吧,因为times还没有更新上去,无法判断哪个页面的访问次数最少并且加入最早。
我们先得更新这个堆中的内容。每次获取堆顶元素并且将times更新到ti上面去然后将times赋值为0。这就是为什么times叫做临时访问次数的原因了。
每次更新完又将这个元素加入到堆里,一起维护,如果说times[a[p.t]]为0(为什么呢,为0代表他已经更新过一次了,更新了一次之后他又出现在了堆顶),那么代表之后也都没有内容了,所以当前的堆顶元素是符合我们条件的。
所以就替换这个页面,然后就可以了。