pb_ds库的讲解和应用举例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mistilteinn/article/details/60325660

之前玩了玩bp_ds库,发现它的确有好用之处,却也有一些缺陷。

这里只介绍了一些常用用法,详情请见:https://gcc.gnu.org/onlinedocs/libstdc%2B%2B/ext/pb_ds/

1、hash

pbds自带两种hash,分别用的拉链法和查探法,后者要快一些(和我手打的差不多),而且空间更少(见后文例题),所以推荐后者。

头文件:

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>

用法:

cc_hash_table是拉链法

gp_hash_table是查探法

除了当数组用外,还支持find和operator[]

例如:__gnu_pbds::gp_hash_table<int,bool> h;

例题:

codevs 1230 元素查找
http://codevs.cn/problem/1230/

我分别测试了一下两种hash

上面的是gp_hash_table。
#include<cstdio>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
__gnu_pbds::gp_hash_table<int,bool> h;
inline int read(){
	int r=0;char c=getchar();
	while(c<'0'||c>'9') {c=getchar();}
	while(c>='0'&&c<='9') {r=r*10+c-'0';c=getchar();}
	return r;
}
int main(){
	int n=read(),m=read(),k;
	while(n--){
		k=read();
		h[k]=true;
	}
	while(m--){
		k=read();
		puts(h[k]?"YES":"NO");
	}
	return 0;
}

2、堆

pbds自带的堆种类很多,但根据我的测试,如果没有合并,stl的优先队列还是更快(包括binary_heap_tag,实际应用中并没有所说的那么快)。所以,也就能用用可并堆了。

头文件:

#include<ext/pb_ds/priority_queue.hpp>

用法:

主要用pairing_heap_tag,配对堆,比thin_heap_tag快

和::priority queue用法大致相同,但多了可并堆的join(), modify() , erase() 等

例如: __gnu_pbds::priority_queue<node,less<node>,pairing_heap_tag> pq;

less是stl里的比较器,需要using namespace std, 也可以换成 greater。 

例题:

bzoj 3040: 最短路(road)

http://www.lydsy.com/JudgeOnline/problem.php?id=3040
#include<iostream>
#include<algorithm>
#include<climits>
#include<cstdio>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
const int M=1000005;
inline int read()
{
    int r=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') {r=r*10+c-'0';c=getchar();}
    return r;
}
struct node
{
    int i;
    ll v;
    node(int a=0,ll c=0){i=a;v=c;}
    bool operator < (node b) const
    {
        return v>b.v;
    }
};
typedef __gnu_pbds::priority_queue<node,less<node>,pairing_heap_tag> heap;//!!!
heap::point_iterator hit[M];
heap pq;
int n;
ll d[M];
int last[1000005],cnt;
struct data{int to,next,v;}e[10000005];
void insert(int u,int v,int w)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
}
inline void setpath()
{
    int T,rxa,rxc,rya,ryc,rp,x,y,z,m;
    x=y=z=0;
    n=read();m=read();
    T=read();rxa=read();rxc=read();rya=read();ryc=read();rp=read();
    int a,b,q=min(n,T);
    for(int i=0;i<q;i++)
    {
        x=((ll)x*rxa+rxc)%rp;
        y=((ll)y*rya+ryc)%rp;
        a=min(x%n+1,y%n+1);
        b=y%n+1;
        insert(a,b,100000000-100*a);
    }
    for(int i=0;i<m-T;i++)
    {
        x=read(),y=read(),z=read();
        insert(x,y,z);
    }
}
ll dijkstra()
{
    for(int i=1;i<=n;i++) d[i]=LLONG_MAX;
    hit[1]=pq.push(node(1,0));
    d[1]=0;
    int o;
    while(!pq.empty())
    {
        o=pq.top().i;
        pq.pop();
        if(o==n) return d[o];
        for(int i=last[o];i;i=e[i].next)
        {
            if(d[e[i].to]>d[o]+e[i].v)
            {
                d[e[i].to]=d[o]+e[i].v;
                if(hit[e[i].to]==0) hit[e[i].to]=pq.push(node(e[i].to,d[e[i].to]));
                else pq.modify(hit[e[i].to],node(e[i].to,d[e[i].to]));
            }
        }
    }
}
int main()
{
    setpath();
    cout<<dijkstra();
    return 0;
}



3、平衡树

pbds最大的好处在于支持名次树和自定义函数

头文件:

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>

用法:

常用rb_tree_tag(红黑数)和splay_tree_tag

可以加tree_order_statistics_node_update以实现名次数

注意他没有multiset一样的功能,如果要存重复元素可以建结构体(见例题)。

相比set多了find_by_order和order_of_key(详见例题

例如:tree<node,null_type,greater<node>,rb_tree_tag,tree_order_statistics_node_update> T;

注意老版本编译器要把null_type换成null_mapped_type。

例题:

2004年NOI全国竞赛 郁闷的出纳员
http://codevs.cn/problem/1286/
#include<cstdio>
#include<iostream>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
struct node{
	int v,id;
	node(int a,int b){v=a;id=b;}
	bool operator >(node b) const
	{return v==b.v?id>b.id:v>b.v;}
};
tree<node,null_mapped_type,greater<node>,rb_tree_tag,tree_order_statistics_node_update> T,TE;
int main(){
	int n,m,k,s=0,q,ans=0;
	char c[10];
	scanf("%d%d",&n,&m);
	while(n--){
		cin>>c[0];scanf("%d",&k);
		if(*c=='I') {k+=s;if(k>=m) T.insert(node(k,n));}
		else if(*c=='A') m-=k,s-=k;
		else if(*c=='S'){
			m+=k,s+=k;
			T.split(node(m,-1),TE);
			ans+=TE.size();
		}
		else if(*c=='F')	
			printf(k>T.size()?"-1\n":"%d\n",T.find_by_order(k-1)->v-s);
	}
	printf("%d\n",ans);
	return 0;
}



4、字典树

这个基本没用,就不讲了。。。


没有更多推荐了,返回首页