保研机试训练Day-08

完整堆操作 && 哈希函数

Posted by Jeffzzc on March 27, 2025

大纲

完整堆操作

维护一个集合,初始时集合为空,支持如下几种操作:

  1. I x,插入一个数 x
  2. PM,输出当前集合中的最小值;
  3. DM,删除当前集合中的最小值(数据保证此时的最小值唯一);
  4. D k,删除第 k 个插入的数;
  5. C k x,修改第 k 个插入的数,将其变为 x

现在要进行 N 次操作,对于所有第 2 个操作,输出当前集合的最小值。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,x,m=0,k;
int a[N],sz,ph[N],hp[N];

void heap_swap(int x,int y){
    swap(ph[hp[x]],ph[hp[y]]);
    swap(hp[x],hp[y]);
    swap(a[x],a[y]);
  
}
void down(int u){
    int t = u;
    if(u*2<=sz && a[u*2]<=a[t]) t = u*2;
    if(u*2+1<=sz && a[u*2+1]<=a[t]) t=u*2+1;
    if(u!=t){
        heap_swap(u,t);
        down(t);
    }
}
void up(int u){
    while(u / 2 && a[u/2] > a[u]){
        heap_swap(u/2,u);
        u/=2;
    }
}
int main(){
    scanf("%d",&n);
    while(n--){
        char op[10];
        scanf("%s",op);
        if(!strcmp(op,"I")){
            scanf("%d",&x);
            sz++;
            m++;
            ph[m] = sz, hp[sz] = m;
            a[sz] = x;
            up(sz);
        }
        else if(!strcmp(op,"PM")){
            printf("%d\n",a[1]);
        }
        else if(!strcmp(op,"DM")){
            heap_swap(1,sz);
            sz--;
            down(1);
        }
        else if(!strcmp(op,"D")){
            scanf("%d",&k);
            k = ph[k];
            heap_swap(k,sz);
            sz--;
            down(k), up(k);
        }
        else{
            scanf("%d%d",&k,&x);
            k = ph[k];
            a[k] = x;
            down(k), up(k);
        }
    }
    return 0;
}

并查集应用:

食物链 AcWing240: 思路是存储到父节点的距离,并且每次做路径压缩的时候都要更新到根节点的距离,最后判断类型就依据到父节点的距离模3的余数来判断

#include<iostream>
using namespace std;
int n,m;
const int N=50010;
int p[N],d[N]; //d[x]表示到x父亲的距离
int find(int x){
    if(p[x]!=x){
        int t = find(p[x]);
        d[x] += d[p[x]];
        p[x] = t;
    }
    return p[x];
}
int main(){
    cin>>n>>m;
    int res=0;
    for(int i=1;i<=n;i++) p[i]=i;
    while(m--){
        int t,x,y;
        cin>>t>>x>>y;
        if(x>n || y>n) res++;
        else{
            int px = find(x), py = find(y);
            if(t==1){
                if(px==py && (d[x] - d[y]) % 3) res++;
                else if(px!=py){
                    p[px] = py;
                    d[px] = d[y] - d[x];
                }
            }
            else{
                if(px==py && (d[x] - d[y] - 1) % 3) res++;
                else if(px!=py){
                    p[px] = py;
                    d[px] = d[y] + 1 - d[x];
                }
            }
        }
    }
    printf("%d\n",res);
    return 0;
}

哈希函数

主要作用: 1.将大范围映射到小范围内(可能有冲突) 2.开放寻址法或者拉链法

首先是拉链法:

#include<iostream>
#include<cstring>
using namespace std;
int n;
const int N=100003;
int h[N],e[N],ne[N],idx;
void search(){
    for(int i=100000;;i++){
        bool flag = true;
        for(int j=2;j*j<=i;j++){
            if(i % j == 0){
                flag = false;
                break;
            }
        }
        if(flag){
            cout<<i<<endl;
            break;
        } 
    }
}
void insert(int x){
    int k = (x % N + N) % N; //余数变为正数
  
    e[idx] = x;
    ne[idx] = h[k];
    h[k] = idx++;
}
bool find(int x){
    int k = (x % N + N) % N;
    for(int i=h[k];i!=-1;i=ne[i]){
        if(e[i]==x) return true;
    }
    return false;
}
int main(){
    // cin.tie(0);cout.tie(0);
    scanf("%d",&n);
    memset(h,-1,sizeof h);
    while(n--){
        char op[2];
        int x;
        scanf("%s%d",op,&x);
        if(*op == 'I'){
            insert(x);
        }
        else{
            if(find(x)) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

然后是开放寻址法:

#include<iostream>
#include<cstring>
using namespace std;
int n;
const int N=200003, null = 0x3f3f3f3f;
int h[N],idx;
void search(){
    for(int i=200000;;i++){
        bool flag = true;
        for(int j=2;j*j<=i;j++){
            if(i % j == 0){
                flag = false;
                break;
            }
        }
        if(flag){
            cout<<i<<endl;
            break;
        } 
    }
}
int find(int x){
    int k = (x % N + N) % N;
    while(h[k] != null && h[k] != x){
        k++;
        if(k == N) k = 0;
    }
    return k;
}
int main(){
    scanf("%d",&n);
    memset(h,0x3f,sizeof h);
    while(n--){
        char op[2];
        int x;
        scanf("%s%d",op,&x);
        int k = find(x);
        if(*op == 'I') h[k] = x;
        else{
            if(h[k] != null) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}