HNOI2005 虚拟内存 线段树+Hash

传送门
题目大意:模拟一个内存系统。
题解:大力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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值