求问:gp_hash_table 等哈希表在什么情况下相比会更优
查看原帖
求问:gp_hash_table 等哈希表在什么情况下相比会更优
312795
qwqszxc45rtnhy678ikj楼主2024/12/21 12:09

例如,在今天我在帮同学调试 P5445 的过程中,发现以下代码在洛谷获得 90pts(MLE),而在我们学校自己搭建的 oj 上可以 AC,使用的是 cc_hash_table:

#include<iostream>
#include<algorithm>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
const int N=3e5+5;
string s,op;
int n,q,pre,suf;
struct Seg{
    int lb[N*4],rb[N*4];
    void build(int u,int l,int r){
        if(l==r){
            lb[u]=rb[u]=l;
            return;
        }
        int mid=(l+r)>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    }
    void pushdown(int u){
        if(lb[u])lb[u<<1]=lb[u],lb[u<<1|1]=lb[u],lb[u]=0;
        if(rb[u])rb[u<<1]=rb[u],rb[u<<1|1]=rb[u],rb[u]=0;
    }
    int qry(int u,int l,int r,int k,int tp){
        if(l==r)
            return tp?rb[u]:lb[u];
        pushdown(u);
        int mid=(l+r)>>1;
        if(k<=mid)return qry(u<<1,l,mid,k,tp);
        else return qry(u<<1|1,mid+1,r,k,tp);
    }
    void mdf(int u,int l,int r,int L,int R,int tp,int x){
        if(L<=l&&r<=R){
            tp?(rb[u]=x):(lb[u]=x);
            return;
        }
        pushdown(u);
        int mid=(l+r)>>1;
        if(L<=mid)mdf(u<<1,l,mid,L,R,tp,x);
        if(R>mid)mdf(u<<1|1,mid+1,r,L,R,tp,x);
    }
}T;
struct Bit{
    cc_hash_table<int,int> val[N];
    void mdf(int x,int y,int k){
        for(int i=x;i<=n+1;i+=i&(-i))
            for(int j=y;j<=n+1;j+=j&(-j))
                val[i][j]+=k;
    }
    int qry(int x,int y){
        int res=0;
        for(int i=x;i;i-=i&(-i))
            for(int j=y;j;j-=j&(-j))
            if(val[i].find(j)!=val[i].end())
                res+=val[i][j];
        return res;
    }
}bit;
void mdf(int a,int c,int b,int d,int x){
    bit.mdf(a,b,x),bit.mdf(c+1,b,-x),bit.mdf(a,d+1,-x),bit.mdf(c+1,d+1,x);
}
void del(int x,int t){
    int l=T.qry(1,1,n+1,x,0),r=T.qry(1,1,n+1,x+1,1);
    T.mdf(1,1,n+1,l,x,1,x),T.mdf(1,1,n+1,x+1,r,0,x+1);
    mdf(l,x,x+1,r,t-q);
    s[x-1]='0';
}
void add(int x,int t){
    int l=T.qry(1,1,n+1,x,0),r=T.qry(1,1,n+1,x+1,1);
    T.mdf(1,1,n+1,l,x,1,r),T.mdf(1,1,n+1,x+1,r,0,l);
    mdf(l,x,x+1,r,q-t);
    s[x-1]='1';
}
int main(){
    // freopen("light.in","r",stdin);
    // freopen("light.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>q>>s;
    T.build(1,1,n+1);
    for(int i=0;i<(int)s.size();i++){
        if(s[i]=='1')add(i+1,0);
    }
    for(int i=1,x,a,b;i<=q;i++){
        cin>>op;
        if(op=="toggle"){
            cin>>x;
            if(s[x-1]=='1')del(x,i);
            else add(x,i);
        }else{
            cin>>a>>b;
            int ans=bit.qry(a,b);
            if(T.qry(1,1,n+1,a,1)>=b)ans-=q-i;
            cout<<ans<<'\n';
        }
    }

    return 0;
}

如果我使用 unordered_map,它将直接通过两边的测试数据:

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
string s,op;
int n,q,pre,suf;
struct Seg{
    int lb[N*4],rb[N*4];
    void build(int u,int l,int r){
        if(l==r){
            lb[u]=rb[u]=l;
            return;
        }
        int mid=(l+r)>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    }
    void pushdown(int u){
        if(lb[u])lb[u<<1]=lb[u],lb[u<<1|1]=lb[u],lb[u]=0;
        if(rb[u])rb[u<<1]=rb[u],rb[u<<1|1]=rb[u],rb[u]=0;
    }
    int qry(int u,int l,int r,int k,int tp){
        if(l==r)
            return tp?rb[u]:lb[u];
        pushdown(u);
        int mid=(l+r)>>1;
        if(k<=mid)return qry(u<<1,l,mid,k,tp);
        else return qry(u<<1|1,mid+1,r,k,tp);
    }
    void mdf(int u,int l,int r,int L,int R,int tp,int x){
        if(L<=l&&r<=R){
            tp?(rb[u]=x):(lb[u]=x);
            return;
        }
        pushdown(u);
        int mid=(l+r)>>1;
        if(L<=mid)mdf(u<<1,l,mid,L,R,tp,x);
        if(R>mid)mdf(u<<1|1,mid+1,r,L,R,tp,x);
    }
}T;
struct Bit{
    unordered_map<int,int> val[N];
    void mdf(int x,int y,int k){
        for(int i=x;i<=n+1;i+=i&(-i))
            for(int j=y;j<=n+1;j+=j&(-j))
                val[i][j]+=k;
    }
    int qry(int x,int y){
        int res=0;
        for(int i=x;i;i-=i&(-i))
            for(int j=y;j;j-=j&(-j))
            if(val[i].find(j)!=val[i].end())
                res+=val[i][j];
        return res;
    }
}bit;
void mdf(int a,int c,int b,int d,int x){
    bit.mdf(a,b,x),bit.mdf(c+1,b,-x),bit.mdf(a,d+1,-x),bit.mdf(c+1,d+1,x);
}
void del(int x,int t){
    int l=T.qry(1,1,n+1,x,0),r=T.qry(1,1,n+1,x+1,1);
    T.mdf(1,1,n+1,l,x,1,x),T.mdf(1,1,n+1,x+1,r,0,x+1);
    mdf(l,x,x+1,r,t-q);
    s[x-1]='0';
}
void add(int x,int t){
    int l=T.qry(1,1,n+1,x,0),r=T.qry(1,1,n+1,x+1,1);
    T.mdf(1,1,n+1,l,x,1,r),T.mdf(1,1,n+1,x+1,r,0,l);
    mdf(l,x,x+1,r,q-t);
    s[x-1]='1';
}
int main(){
    // freopen("light.in","r",stdin);
    // freopen("light.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>q>>s;
    T.build(1,1,n+1);
    for(int i=0;i<(int)s.size();i++){
        if(s[i]=='1')add(i+1,0);
    }
    for(int i=1,x,a,b;i<=q;i++){
        cin>>op;
        if(op=="toggle"){
            cin>>x;
            if(s[x-1]=='1')del(x,i);
            else add(x,i);
        }else{
            cin>>a>>b;
            int ans=bit.qry(a,b);
            if(T.qry(1,1,n+1,a,1)>=b)ans-=q-i;
            cout<<ans<<'\n';
        }
    }

    return 0;
}

在当我使用 gp_hash_table 时,我在学校的 oj 上如何卡常都卡不过去,无法通过(TLE),但是在洛谷直接过了。

(这里就不赋代码了,直接把 cc_hash_table 的那份改成 gp_hash_table 就为我所使用的代码)

因为我不太懂 pbds 或者说 STL 的东西,按理来说 gp_hash_table 会更快,但是却在我校 oj 中出现明显的效率差异

所以求问以下问题:

  1. 代码是不是写的哪里有问题导致 gp_hash_table 的实现会 TLE
  2. 这三者到底有什么优劣,该如何选择
2024/12/21 12:09
加载中...