BZOJ 2733([HNOI2012]永无乡-Treap启发式合并)

2733: [HNOI2012]永无乡
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3219 Solved: 1706
[Submit][Status][Discuss]
Description

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。

Input

输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000

对于 100%的数据 n≤100000,m≤n,q≤300000

Output

对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。

Sample Input
5 1

4 3 2 5 1

1 2

7

Q 3 2

Q 2 1

B 2 3

B 1 5

Q 2 1

Q 2 4

Q 2 3

Sample Output
-1

2

5

1

2

用并查集维护连通性,再用Treap维护第k大

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <cstdlib>
#include <queue>
#include <stack>
#include <set>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (20161119)
#define ALL(x) (x).begin(),(x).end()
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pri(a,n) for(int i=1;i<n;i++) cout<<a[i]<<' ';cout<<a[n]<<endl;
typedef long long ll;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
#define MAXN (100000*4)
int n,m;
struct treap{
    ll rnd[MAXN],v[MAXN],w[MAXN];
    int size[MAXN],l[MAXN],r[MAXN],cnt;
    void mem() {
        MEM(size) MEM(rnd) MEM(l) MEM(r) MEM(v) MEM(w)
        cnt=0;
    }
    void update(int x)
    {
        size[x]=size[l[x]]+size[r[x]]+w[x];
    }
    void rturn(int &k)
    {
        int t=l[k];l[k]=r[t];r[t]=k;update(k);update(t);k=t;
    }
    void lturn(int &k)
    {
        int t=r[k];r[k]=l[t];l[t]=k;update(k);update(t);k=t;
    }
    void insert(int &x,ll rank,int y=0) 
    {
        if(!x)
        {
            if (y) {
                x=y;
                l[x]=r[x]=0;
                rnd[x]=rand();
                size[x]=w[x]; return;
            }
            x=++cnt;
            v[x]=rank; l[x]=r[x]=0;
            rnd[x]=rand();size[x]=w[x]=1;
            return ;
        }
        size[x]++;
        if(v[x]<rank)
        {
            insert(r[x],rank,y);
            if(rnd[r[x]]<rnd[x])lturn(x);
        }
        else if (v[x]>rank)
        {
            insert(l[x],rank,y);
            if(rnd[l[x]]<rnd[x]) rturn(x);
        }else w[x]++ ;
    }
    void unite(int &x,int y) {
        if (!y) return ;
        unite(x,l[y]);
        unite(x,r[y]);
        Rep(i,w[y]) insert(x,v[y],y);
    }
    void del(int &x,ll val) {
        if (!x) return ;
        if (v[x]==val) {
            if (w[x]>1) {--w[x]; --size[x]; return; }
            if (!l[x]||!r[x]) x=l[x]+r[x];
            else if (rnd[l[x]]<rnd[r[x]]) rturn(x),del(x,val);
            else lturn(x),del(x,val);
        }
        else {
            --size[x];
            if (val<v[x]) del(l[x],val); else del(r[x],val);
        }
    }
    // return the pointer
    int lower_bound(int x,ll rank) {
        int ans=-1;
        if (!x) return ans;
        if (v[x]<=rank) {
            ans=lower_bound(r[x],rank);
            if (ans==-1) ans=x;
        } else ans=lower_bound(l[x],rank);
        return ans;
    }
    int upper_bound(int x,ll rank) {
        int ans=-1;
        if (!x) return ans;
        if (v[x]>rank) {
            ans=upper_bound(l[x],rank);
            if (ans==-1) ans=x;
        } else ans=upper_bound(r[x],rank);
        return ans;
    }
    void pri(int x){
        if (l[x]) pri(l[x]);
        cout<<v[x]<<' ';
        if (r[x]) pri(r[x]);
    }
    int get_rank(int x,ll val) {
        if (!x) return 0;
        if (v[x]==val) return size[l[x]]+1;
        else if (val<v[x]) return get_rank(l[x],val);
        else return get_rank(r[x],val)+size[l[x]]+w[x];
    }
    int how_many_number_lower_than_x(int x,ll val) {
        if (!x) return 0;
        if (v[x]==val) return size[l[x]];
        else if (val<v[x]) return how_many_number_lower_than_x(l[x],val);
        else return how_many_number_lower_than_x(r[x],val)+size[l[x]]+w[x];
    }
    int get_kth(int x,int k) {
        if (!x) return -1;
        if (k<=size[l[x]]) return get_kth(l[x],k);
        else if (k<=size[l[x]]+w[x]) return x;
        else return get_kth(r[x],k-size[l[x]]-w[x]);
    }
}T;
int root[MAXN];
class bingchaji
{
public:
    int father[MAXN],n,cnt,sz[MAXN];
    void mem(int _n)
    {
        n=cnt=_n;
        For(i,n) father[i]=i,sz[i]=1;
    }
    int getfather(int x) 
    {
        if (father[x]==x) return x;
        return father[x]=getfather(father[x]);
    }
    void unite(int x,int y)
    {
        x=getfather(x);
        y=getfather(y);
        if (x^y) {
            --cnt;
            if (sz[x]>sz[y]) swap(x,y);
            father[x]=y;
            sz[y]+=sz[x];
            T.unite(root[y],root[x]);
        }
    }
    bool same(int x,int y)
    {
        return getfather(x)==getfather(y);
    }
}S;
int a[MAXN];
int main() {
    // freopen("bzoj2733.in","r",stdin);
    n=read();m=read();  
    S.mem(n);
    For(i,n) a[i]=read(),T.insert(root[i],a[i]);
    For(i,m) {
        int x=read(),y=read();
        S.unite(x,y);
    }
    int q=read();
    For(i,q) {
        char opt[10];scanf("%s",opt);
        int x=read(),y=read();
        switch (opt[0]) {
            case 'B':S.unite(x,y);break;
            case 'Q':printf("%d\n",T.get_kth(root[S.getfather(x)],y));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值