zoukankan      html  css  js  c++  java
  • BZOJ1206:[HNOI2005]虚拟内存

    我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1206

    上周因为一些原因脑子不是很好用,然后上周从没做到过一遍(A)题。然后这周一来学校就感冒了……室友晚上睡觉打喷嚏飞我一脸……然后脑子晕乎乎的……

    但是我居然一遍(A)了??
    此处输入图片的描述

    简直假爆了(虽然我觉得用线段树的话一遍(A)应该很正常才对……换Splay可能就得GG)。

    首先,我们先将数据离线读入,然后离散化,因为(P_ileqslant10^9)

    然后我们种一颗线段树,线段树(n)个叶子结点就是内存的(n)个页面,对于每个结点,我们都记录它所对应区间的满足题意要求的“最小值”(就是假如有一个新访问需要替换原有的位置,应该被替换的的位置,空白页也算)在线段树里的位置,访问次数,最早进来的时间还有离散化后的页编号(初始为inf)。还要记录对于每个页它在线段树里对应哪个叶子结点(如果没有在线段树里就是0)。然后对于每个询问,我们根据题意模拟:

    如果该询问页在线段树里,直接从叶子一路往上跟新信息。

    如果它不在,那么就找整个内存里的“最小值”,并且用该询问的信息替换掉。

    时间复杂度:(O(mlogn))

    空间复杂度:(O(m+n))

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int inf=2e9;
    const int maxn=1e5+5,maxm=1e6+5;
    
    int inseg[maxm];//insge[v]表示v号页在线段树的叶节点的编号是多少
    int n,m,ans,cnt;
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    
    struct page {
    	int v,id,rk;
    }a[maxm];
    
    bool cmp_v(page a,page b) {
    	return a.v<b.v;//按照v从大到小排序
    }
    
    bool cmp_id(page a,page b) {
    	return a.id<b.id;//按照id从大到小排序
    }
    
    struct treenode {
    	int tot,tim,pos,v;
    	bool operator <(const treenode &a)const {
    		if(tot==a.tot)return tim<a.tim;
    		return tot<a.tot;//访问次数为第一关键字,进入内存时间为第二关键字
    	}
    };
    
    struct segment_tree {
    	treenode tree[maxn*4];
    
    	void update(int p) {
    		if(tree[p<<1]<tree[p<<1|1])tree[p]=tree[p<<1];
    		else tree[p]=tree[p<<1|1];//哪边的替换优先级更高就用哪边更新父亲
    	}
    	
    	void build(int p,int l,int r) {
    		if(l==r) {
    			tree[p].tot=tree[p].tim=0;
    			tree[p].v=inf,tree[p].pos=l;//初始的页都是inf页,然后都是访问过0次的
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(p<<1,l,mid);
    		build(p<<1|1,mid+1,r);
    		update(p);
    	}
    
    	void add(int p,bool isleave) {
    		if(isleave)tree[p].tot++;//如果是叶子结点直接加一次访问数
    		else update(p);//不然就更新自己的信息,因为他的子树信息更新了
    		if(p==1)return;//到根节点就直接return
    		add(p>>1,0);//去更新父亲结点
    	}
    
    	void change(int p,int l,int r,int T,int v) {
    		if(l==r) {
    			if(tree[p].v!=inf)inseg[tree[p].v]=0;//把原先占据该结点的页信息抹掉
    			inseg[v]=p;
    			tree[p].v=v;
    			tree[p].tot=1;
    			tree[p].tim=T;//更新该结点
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(tree[p].pos<=mid)change(p<<1,l,mid,T,v);
    		else change(p<<1|1,mid+1,r,T,v);//找“最小值”去change
    		update(p);
    	}
    }T;
    
    int main() {
    	n=read(),m=read();a[0].v=inf;
    	for(int i=1;i<=m;i++)
    		a[i].id=i,a[i].v=read();
    	sort(a+1,a+m+1,cmp_v);
    	for(int i=1;i<=m;i++)
    		if(a[i].v==a[i-1].v)a[i].rk=cnt;
    		else a[i].rk=++cnt;
    	sort(a+1,a+m+1,cmp_id);//离散化
    	T.build(1,1,n);//建树
    	for(int i=1;i<=m;i++) {
    		if(inseg[a[i].rk])T.add(inseg[a[i].rk],1),ans++;//如果该询问存在于内存中就增加访问次数
    		else T.change(1,1,n,i,a[i].rk);//否则替换掉一个符合要求的页
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Mac 应用程序中的App在Launchpad中不显示
    oh-my-zsh的安装
    用Lambda 表达式实现Runnable
    用Lambda 表达式实现Runnable
    记录Nacos配置Mysql数据库连接失败解决
    Mac最好用的终端iTerm2安装及配置
    MySQL安装设置密码策略问题
    构建微服务模块流程
    dependencies与dependencyManagement的区别
    winSocket 2 简单的可持续的socket
  • 原文地址:https://www.cnblogs.com/AKMer/p/9106026.html
Copyright © 2011-2022 走看看