HNOI2005 虚拟内存 线段树+Hash

版权声明:本文为DyingShu原创文章,转载请注明出处哦。 https://blog.csdn.net/DyingShu/article/details/82251208

传送门
题目大意:模拟一个内存系统。
题解:大力Hash+线段树。
Hash记录元素是否存在,线段树寻找访问次数最少的页码。
用指针板线段树卡了卡常,居然混到BZOJ的rank1了OvO

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 10001;
const int MAXM = 1000001;
const int MOD = 1000007;

int n, m;
int Ans;

struct Node{
    int l, r;
    int Val, Pos, Tim, Page; //访问次数/位置/时间/现在存的页
    Node *left, *right;
    Node(){
        l = r = Pos = Tim = Page = 0;
        left = right = NULL;
    }
}t[100001];
int tot;
Node *root;

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int k = 0; char ch = nc();
    while(ch < '0' || ch > '9') ch = nc();
    while(ch >= '0' && ch <= '9') k = (k << 3) + (k << 1) + ch - 48, ch = nc();
    return k;
}

struct HASH{
    int Val[MAXM], Pos[MAXM], Tag[MAXM], fir[MOD + 5], nxt[MAXM], cnt;
    inline void Init(){memset(fir, -1, sizeof(fir));}
    inline void Insert(int v, int pos){
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
            if(Val[i] == v){Tag[i] = 1, Pos[i] = pos; return;}
        }
        Pos[cnt] = pos; Val[cnt] = v; Tag[cnt] = 1;
        nxt[cnt] = fir[v % MOD]; fir[v % MOD] = cnt++;
    }
    inline int Find(int v){ //查找值为v的数,返回内存页位置
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
            if(Val[i] == v) if(Tag[i]) return Pos[i];
        }
        return -1;
    }
    inline void Delete(int v){
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
            if(Val[i] == v){Tag[i] = 0; return;}
        }
    }
}Hash;

#define mid ((u->l + u->r) >> 1)
inline void Pushup(Node *u){
    if(u->left->Val != u->right->Val){
        if(u->left->Val > u->right->Val){
            u->Val = u->right->Val;
            u->Tim = u->right->Tim;
            u->Pos = u->right->Pos;
            u->Page = u->right->Page;
        }
        else{
            u->Val = u->left->Val;
            u->Tim = u->left->Tim;
            u->Pos = u->left->Pos;
            u->Page = u->left->Page;
        }
    }
    else{
        if(u->left->Tim > u->right->Tim){
            u->Val = u->right->Val;
            u->Tim = u->right->Tim;
            u->Pos = u->right->Pos;
            u->Page = u->right->Page;
        }
        else{
            u->Val = u->left->Val;
            u->Tim = u->left->Tim;
            u->Pos = u->left->Pos;
            u->Page = u->left->Page;
        }
    }
}
inline void Build(Node *u, int l, int r){
    u->l = l, u->r = r; if(l == r){u->Pos = l; return;}
    u->left = &t[tot++], u->right = &t[tot++];
    Build(u->left, l, mid), Build(u->right, mid + 1, r);
    Pushup(u);
}
inline void Modify(Node *u, int x, int tim, int page){
    if(u->l == u->r){u->Tim = tim, u->Val = 1, u->Page = page; return;}
    if(x <= mid) Modify(u->left);
    else Modify(u->right);
    Pushup(u);
}
inline void Add(Node *u, int x){
    if(u->l == u->r){u->Val++; return;}
    if(x <= mid) Add(u->left); else Add(u->right);
    Pushup(u);
}
#undef mid

int main(){
    n = read(), m = read();
    Hash.Init();
    root = &t[tot++]; Build(root, 1, n);
    for(register int i = 1; i <= m; ++i){
        int Val = read(); //读入第i条操作
        int k = Hash.Find(Val);
        if(k != -1){Add(root, k); Ans++;}
        else{
            if(root->Page) Hash.Delete(root->Page);
            Hash.Insert(Val, root->Pos);
            Modify(root, root->Pos, i, Val);
        }
    }
    printf("%d", Ans);
    return 0;
}

没过之前调了很久的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 10001;
const int MAXM = 1000001;
const int MOD = 1000007;

int n, m;
int Ans;
int cur;
bool flag;

struct Node{
    int Val, Pos, Tim, Page; //访问次数/位置/时间/现在存的页
}t[MAXN << 2];
//int Now[MAXN]; //现在存的页

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int k = 0; char ch = nc();
    while(ch < '0' || ch > '9') ch = nc();
    while(ch >= '0' && ch <= '9') k = (k << 3) + (k << 1) + ch - 48, ch = nc();
    return k;
}

struct HASH{
    int Val[MOD + 5], Pos[MOD + 5], Tag[MOD + 5], fir[MOD + 5];
    int nxt[MOD + 5], cnt;
    inline void Init(){memset(fir, -1, sizeof(fir));}
    inline void Insert(int v, int pos){
//		printf("v = %d, fir = %d\n", v, fir[v % MOD]);
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
//			printf("Val = %d\n", Val[i]);
            if(Val[i] == v){Tag[i] = 1, Pos[i] = pos; return;}
        }
//		printf("???");
//		Val[cnt] = v, Tag[cnt] = 1, nxt[cnt] = fir[v % MOD], fir[v % MOD] = cnt++;
        Pos[cnt] = pos; Val[cnt] = v; Tag[cnt] = 1;
        nxt[cnt] = fir[v % MOD]; fir[v % MOD] = cnt++;
    }
    /*inline bool Find(int v){ //查找值为v的数是否存在
//		printf("v = %d, fir = %d\n", v, fir[v % MOD]);
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
//			printf("Val = %d, v = %d\n", Val[i], v);
            if(Val[i] == v) if(Tag[i]) return true;
        }
        return false;
    }*/
    inline int Find(int v){ //查找值为v的数,返回内存页位置
//		printf("v = %d, fir = %d\n", v, fir[v % MOD]);
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
//			printf("Val = %d, v = %d\n", Val[i], v);
            if(Val[i] == v) if(Tag[i]) return Pos[i];
        }
        return -1;
    }
    inline void Delete(int v){
//		printf("!!v = %d\n", v);
        for(int i = fir[v % MOD]; i != -1; i = nxt[i]){
            if(Val[i] == v){Tag[i] = 0; return;}
        }
    }
}Hash;

struct Segmemnt_Tree{
    #define mid ((l + r) >> 1)
    inline Node Min(Node a, Node b){
//		if(a.Pos == 4 && b.Pos == 5){
//			printf("%d %d\n", a.Page, b.Page);
//			printf("%d %d\n", a.Tim, b.Tim);
//			printf("%d %d\n", a.Val, b.Val);
//			printf("\n");
//		}		
//		if(a.Val == b.Val) return a.Tim < b.Tim ? a : b; //时间早的
//		return a.Val < b.Val ? a : b; //访问次数少的

        if(a.Val != b.Val) return a.Val < b.Val ? a : b; //访问次数少的
        return a.Tim < b.Tim ? a : b; //时间早的
    }
    inline void Build(int u, int l, int r){
        if(l == r){t[u].Pos = l, t[u].Tim = t[u].Val = t[u].Page = 0; return;}
        Build(u << 1, l, mid), Build(u << 1 | 1, mid + 1, r);
        t[u] = Min(t[u << 1], t[u << 1 | 1]);
    }
    inline void Modify(int u, int l, int r, int x, int tim, int page){
        if(l == r){
//			printf("")
//			printf("t[u].Pos = %d\n", t[u].Pos);
//			if(t[u].Val){
//				printf("!");
//				Hash.Delete(Now[t[u].Pos]);
//			}
            if(t[u].Page) Hash.Delete(t[u].Page);
            t[u].Tim = tim, t[u].Val = 1, t[u].Page = page;
//			printf("tim[%d] = %d\n", Now[x], tim);
//			printf("t[u].Pos = %d\n", t[u].Pos);
            return;
        }
        if(x <= mid) Modify(u << 1, l, mid, x, tim, page);
        else Modify(u << 1 | 1, mid + 1, r, x, tim, page);
        t[u] = Min(t[u << 1], t[u << 1 | 1]);
    }
    inline void Add(int u, int l, int r, int x){
        if(l == r){
            t[u].Val++;
//			if(t[u].Page == 10){
//				printf("~%d %d\n", t[u].Page, t[u].Val);
//			}
            return;
        }
        if(x <= mid) Add(u << 1, l, mid, x);
        else Add(u << 1 | 1, mid + 1, r, x);
        t[u] = Min(t[u << 1], t[u << 1 | 1]);
    }
    #undef mid
}T;

int main(){
    n = read(), m = read();
    Hash.Init(); T.Build(1, 1, n);
    for(int i = 1; i <= m; i++){
        int Val = read(); //读入第i条操作
//		printf("Min = %d, Now = %d\n", t[1].Pos, Now[t[1].Pos]);
        int k = Hash.Find(Val);
//		printf("Val = %d, k = %d\n", Val, k);
//		if(Hash.Find(Val)){//a
        if(k != -1){//a
//			printf("i = %d, Val = %d, k = %d\n", i, Val, k);
            T.Add(1, 1, n, k);
            Ans++;
//			printf("\n");
//			continue;
        }
        else{
//			int c = Hash.Find(Val);
//			printf("c = %d\n", c);
//			Node Tmp;
//			if(cur + 1 <= n){ //b
//				cur++;
//				printf("cur = %d\n", cur);
//				Hash.Insert(Val, cur);
//				Tmp.Pos = cur, Tmp.Tim = i, Tmp.Val = 1;
//				T.Modify(1, 1, n, cur, Tmp);
//			}
//			else{ //c
//				printf("Val = %d\n", Val);
                int P = t[1].Pos;
//				printf("k = %d, last = %d\n", k, Now[k]);
//				Hash.Delete(Now[k]); //删除
//				Tmp.Pos = k, Tmp.Tim = i, Tmp.Val = 1;
                Hash.Insert(Val, P);
                T.Modify(1, 1, n, P, i, Val);
//				Now[k] = Val;
//			}
        }
//		printf("i = %d, val = %d, Ans = %d\n", i, Val, Ans);
//		printf("\n");
    }
    printf("%d", Ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/DyingShu/article/details/82251208