zoukankan      html  css  js  c++  java
  • HNOI2012 永无乡 无旋Treap

    题目描述

    永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 aaa 出发经过若干座(含 000 座)桥可以 到达岛 bbb ,则称岛 aaa 和岛 bbb 是连通的。

    现在有两种操作:

    B x y 表示在岛 xxx 与岛 yyy 之间修建一座新桥。

    Q x k 表示询问当前与岛 xxx 连通的所有岛中第 kkk 重要的是哪座岛,即所有与岛 xxx 连通的岛中重要度排名第 kkk 小的岛是哪座,请你输出那个岛的编号。

    输入输出格式

    输入格式:

    第一行是用空格隔开的两个正整数 nnn 和 mmm ,分别表示岛的个数以及一开始存在的桥数。

    接下来的一行是用空格隔开的 nnn 个数,依次描述从岛 111 到岛 nnn 的重要度排名。随后的 mmm 行每行是用空格隔开的两个正整数 aia_iaibib_ibi ,表示一开始就存在一座连接岛 aia_iai 和岛 bib_ibi 的桥。

    后面剩下的部分描述操作,该部分的第一行是一个正整数 qqq ,表示一共有 qqq 个操作,接下来的 qqq 行依次描述每个操作,操作的 格式如上所述,以大写字母 QQQ 或 BBB 开始,后面跟两个不超过 nnn 的正整数,字母与数字以及两个数字之间用空格隔开。

    输出格式:

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

    输入输出样例

    输入样例#1: 
    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
    输出样例#1: 
    -1
    2
    5
    1
    2

    说明

    对于 20% 的数据 n≤1000,q≤1000n leq 1000, q leq 1000n1000,q1000

    对于 100% 的数据 n≤100000,m≤n,q≤300000n leq 100000, m leq n, q leq 300000 n100000,mn,q300000

    提交地址 : Luogu;

          bzoj

    用并查集及维护, 无旋Treap直接启发式合并水过

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define maxn 100010
    
    int n, m;
    int rt[maxn], tot;
    
    struct fhq
    {
        int ch[2];
        int val;
        int pri;
        int siz;
    }t[maxn];
    
    int find(int x)
    {
        return x == rt[x] ? x : rt[x] = find(rt[x]);
    }
    
    void pushup(int o)
    {
        t[o].siz = t[t[o].ch[0]].siz + t[t[o].ch[1]].siz + 1;
    }
    
    void Split(int o, int k, int &x, int &y)
    {
        if(!o) x = y = 0;
        else
        {
            if(t[o].val <= k)
            {
                x = o;
                Split(t[o].ch[1], k, t[o].ch[1], y);
            }
            else
            {
                y = o;
                Split(t[o].ch[0], k, x, t[o].ch[0]);
            }
            pushup(o);
        }
    }
    
    int Merge(int x, int y)
    {
        if(!x || !y) return x + y;
        if(t[x].pri < t[y].pri) 
        {
            t[x].ch[1] = Merge(t[x].ch[1], y);
            pushup(x);
            return x;
        }
        else
        {
            t[y].ch[0] = Merge(x, t[y].ch[0]);
            pushup(y);
            return y;
        }
        
    }
    
    void insert(int &root, int y)
    {
        int a, b;
        int v = t[y].val;
        Split(root, v, a, b);
        root =Merge(Merge(a, y), b);
    }
    
    void DFS(int x, int &y)
    {
        if(!x) return;
        DFS(t[x].ch[0], y);
        DFS(t[x].ch[1], y);
        t[x].ch[0] = t[x].ch[1] = 0;
        insert(y, x);
    }
    
    int HeBing(int x, int y)
    {
        if(t[x].siz > t[y].siz) swap(x, y);
        DFS(x, y);
        return y;
    }
    
    int K_th(int o, int k)
    {
        while(1)
        {
            if(k <= t[t[o].ch[0]].siz)
            {
                o = t[o].ch[0];
            }
            else if(k == t[t[o].ch[0]].siz + 1)
            {
                return o;
            }
            else
            {
                k -= t[t[o].ch[0]].siz + 1;
                o = t[o].ch[1];
            }
        }
    }
    
    int sz[maxn], old[maxn];
    
    int main()
    {
        srand(987789213);
        cin >> n >> m;
        memset(old, -1, sizeof old);
        for(register int i = 1 ; i <= n ; i ++)
        {
            scanf("%d", &t[i].val);
            t[i].pri = rand();
            t[i].siz = 1;
            rt[i] = i;
            old[t[i].val] = i;
            sz[i] = 1;
        }
        
        for(register int i = 1 ; i <= m ; i ++)
        {
            int a, b, c;
            scanf("%d%d", &a, &b);
            int fx = find(a), fy = find(b);
            if(fx == fy) continue;
            
            c = HeBing(rt[a], rt[b]);
            
            fx = find(a), fy = find(b);
            
            rt[fx] = rt[fy] = c;
            
            rt[c] = c;
        }
        
        int q;
        cin >> q;
        while(q--)
        {
            char ch;
            int x, y;
            int a, b, c;
            cin >> ch;
            scanf("%d%d", &x, &y);
            if(ch == 'Q')
            {
                int fx = find(x);
                printf("%d
    ", old[t[K_th(rt[x], y)].val]);
            }
            else
            {
                int fx = find(x), fy = find(y);
                if(fx == fy) continue;
                c = HeBing(rt[x], rt[y]);
                fx = find(x), fy = find(y);
                
                rt[fx] = rt[fy] = c;
                rt[c] = c;
                
            }
        }
        return 0;
        
    }
    zZhBr
  • 相关阅读:
    Printing a DataGridView on DotNet Framework
    对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式
    PetShop配置readme
    关于DGVPrinter.cs中的PrintRange
    foobar2000 0.9.5正式版放出
    Another DataGridView Printer
    getline及读文件总结
    C++中文件的读取操作,如何读取多行数据,如何一个一个的读取数据
    vector的clear和swap
    写程序前不需指定数组中的常量,而是动态编译中决定
  • 原文地址:https://www.cnblogs.com/BriMon/p/8983601.html
Copyright © 2011-2022 走看看