pb_ds库的讲解和应用举例

来源:互联网 发布:线条随鼠标特效源码 编辑:程序博客网 时间:2024/06/10 08:28

之前玩了玩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、字典树

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


2 0
原创粉丝点击