1. 题目

BZOJ 传送门= ̄ω ̄=
LUOGU 传送门= ̄ω ̄=
CODEVS 传送门= ̄ω ̄=

2. 题解

真是气死人啦!
调了一晚上+一个课间操,都没找出 bug。
重写了 3 次 treap,第一次用指针,第二次用 vector,第三次用静态数组。。。
都错的一模一样!
为什么呢?
中午绝望的我无意中看了看代码中不是 treap 的地方。。。
merge 函数中这句话:

a=findf(a),findf(b);

。。。
你大爷啊!我居然挂在了这里!。。。应该这样写:

a=findf(a),b=findf(b);

。。。。。。。。。。。。。。。。
想起昨天考试,>=写成了>,从 100 分掉到了 10 分。。。。
一种来到非洲的感觉油然而生!
好吧,其实这题很水,就是个并查集维护集合关系,然后启发式合并。
思路具体去看我以前写的用 pb_ds 解决的那个博客吧:
https://www.mina.moe/?p=786

treap 代码:
指针 treap 用了个小技巧,本来节点的构造函数会把节点的 l 和 r 指到 NULL 上。我把它指到了一个叫 def(default) 的节点上,这样可以不用每次都判断是否为 NULL 防止段错误了。
代码 1(指针 treap):

#include <bits/stdc++.h>
using namespace std;
template<typename _Tp>void IN(_Tp&dig)
{
    char c=getchar();dig=0;
    while(!isdigit(c))c=getchar();
    while(isdigit(c))dig=dig*10+c-'0',c=getchar();
}
struct N{int v,d,f,s;N*l,*r;N();}*def=new N;
N::N(){v=d=f=s=0,l=r=def;}
struct treap
{
    int size;N*root;
    treap(){size=0,root=def;}
    void update(N*&a){a->s=a->l->s+a->r->s+1;}
    void lrot(N*&a){N*b=a->r;a->r=b->l,b->l=a,b->s=a->s,update(a),a=b;}
    void rrot(N*&a){N*b=a->l;a->l=b->r,b->r=a,b->s=a->s,update(a),a=b;}
    void insert(N*&a,int v,int d)
    {
        if(a==def)
        {
          a=new N;
          a->v=v,a->d=d,a->f=rand(),a->s=1,size++;
          return;
        }
        if(v<a->v){insert(a->l,v,d);if(a->l->f<a->f)rrot(a);}
        else if(v>a->v){insert(a->r,v,d);if(a->r->f<a->f)lrot(a);}
        update(a);
    }
    int kth(N*&a,int k)
    {
        if(a==def)return -1;
        if(k==a->l->s+1)return a->d;
        if(k<=a->l->s)return kth(a->l,k);
        return kth(a->r,k-a->l->s-1);
    }
    void jion(N*&a,treap&b)
    {
        if(a==def)return;
        b.insert(b.root,a->v,a->d),jion(a->l,b),jion(a->r,b);
    }
}t[100005];
int n,m,h[100005],f[100005],q;
int findf(int a){return a==f[a]?a:f[a]=findf(f[a]);}
void merge(int a,int b)
{
    a=findf(a),b=findf(b);
    if(t[h[a]].size>t[h[b]].size)swap(h[a],h[b]);
    t[h[a]].jion(t[h[a]].root,t[h[b]]),f[a]=b;
}
int main()
{
    IN(n),IN(m),srand(n);
    for(int i=1,a;i<=n;i++)f[i]=h[i]=i,IN(a),t[i].insert(t[i].root,a,i);
    for(int i=1,a,b;i<=m;i++)IN(a),IN(b),merge(a,b);
    IN(q);
    for(int i=1,a,b;i<=q;i++)
    {
        char c=getchar();
        while(!isalpha(c))c=getchar();
        IN(a),IN(b);
        if(c=='Q')a=h[findf(a)],printf("%d\n",t[a].kth(t[a].root,b));
        else merge(a,b);
    }
    return 0;
}

静态数组大小开 $nlogn$的大小(稍微开大一点)就行了,因为启发式合并复杂度为 $nlogn$
代码 2(静态数组 treap):

#include <bits/stdc++.h>
using namespace std;
template<typename _Tp>void IN(_Tp&dig)
{
    char c=getchar();dig=0;
    while(!isdigit(c))c=getchar();
    while(isdigit(c))dig=dig*10+c-'0',c=getchar();
}
static const int ns=3000000;
int n,m,h[100005],f[100005],q,tl[ns],tr[ns],ts[ns],tv[ns],td[ns],tf[ns],tcnt;
struct treap
{
    int size,root;
    treap(){size=root=0;}
    void update(int a){ts[a]=ts[tl[a]]+ts[tr[a]]+1;}
    void lrot(int&a){int b=tr[a];tr[a]=tl[b],tl[b]=a,ts[b]=ts[a],update(a),a=b;}
    void rrot(int&a){int b=tl[a];tl[a]=tr[b],tr[b]=a,ts[b]=ts[a],update(a),a=b;}
    void insert(int&a,int v,int d)
    {
        if(!a){tcnt++,size++,a=tcnt;tf[a]=rand(),tv[a]=v,td[a]=d,ts[a]=1;return;}
        if(v<tv[a]){insert(tl[a],v,d);if(tf[tl[a]]<tf[a])rrot(a);}
        if(v>tv[a]){insert(tr[a],v,d);if(tf[tr[a]]<tf[a])lrot(a);}
        update(a);
    }
    int kth(int&a,int k)
    {
        if(!a)return -1;
        if(ts[tl[a]]+1==k)return td[a];
        if(ts[tl[a]]+1>k)return kth(tl[a],k);
        return kth(tr[a],k-ts[tl[a]]-1);
    }
    void jion(int&a,treap&b)
    {
        if(!a)return;
        b.insert(b.root,tv[a],td[a]),jion(tl[a],b),jion(tr[a],b);
    }
}t[100005];
int findf(int a){return (f[a]==a)?a:f[a]=findf(f[a]);}
void merge(int a,int b)
{
    a=findf(a),b=findf(b);
    if(t[h[a]].size>t[h[b]].size)swap(h[a],h[b]);
    t[h[a]].jion(t[h[a]].root,t[h[b]]),f[a]=b;
}
int main()
{
    IN(n),IN(m),srand(n);
    for(int i=1,a;i<=n;i++)f[i]=h[i]=i,IN(a),t[i].insert(t[i].root,a,i);
    for(int i=1,a,b;i<=m;i++)IN(a),IN(b),merge(a,b);
    IN(q);
    for(int i=1,a,b;i<=q;i++)
    {
        char c=getchar();
        while(!isalpha(c))c=getchar();
        IN(a),IN(b);
        if(c=='Q')a=h[findf(a)],printf("%d\n",t[a].kth(t[a].root,b));
        else merge(a,b);
    }
    return 0;
}
分类: 文章

XZYQvQ

炒鸡辣鸡的制杖蒟蒻一枚QvQ