zoukankan      html  css  js  c++  java
  • P3224 [HNOI2012]永无乡

    题目描述

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

    现在有两种操作:

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

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

    输入输出格式

    输入格式:

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

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

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

    输出格式:

    对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 -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 leq 1000, q leq 1000n1000,q1000

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

    题解

    这道题要求我们执行两个操作。1.判断是否在同一个集合 2.查找联通快第k小值

    操作一我们可以用并查集维护,操作二的话,我们可以用splay维护

    但合并怎么做呢?我看了看题解,发现有个叫做启发式合并的神器玩意儿

    简而言之,就是合并两个splay时,把节点数较少的splay中每一个点都取出来插入另一个splay中(好暴力啊……暴力mo不可取……)

    时间复杂度是O(n log n)的

    原因?能用就好要什么原因

    具体的实现请看代码

      1 //minamoto
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<algorithm>
      5 #include<cstring>
      6 #define N 500050
      7 using namespace std;
      8 inline int read(){
      9     char ch;bool flag=0;int res;
     10     while(!isdigit(ch=getchar()))
     11         (ch=='-')&&(flag=true);
     12     for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0');
     13     (flag)&&(res=-res);
     14     return res;
     15 }
     16 int n,m;
     17 struct node{
     18     int val,father,size,ch[2];
     19 } e[N];
     20 int cnt,root[N],f[N],h[N];
     21 int ff(int x){
     22     return f[x]==x?x:f[x]=ff(f[x]);
     23 }
     24 void pushup(int x){
     25     e[x].size=e[e[x].ch[0]].size+e[e[x].ch[1]].size+1;
     26 }
     27 int identify(int x){
     28     return e[e[x].father].ch[1]==x;
     29 }
     30 void connect(int x,int f,int son){
     31     e[x].father=f,e[f].ch[son]=x;
     32 }
     33 void rotate(int x){
     34     int y=e[x].father,z=e[y].father;
     35     int yson=identify(x),zson=identify(y);
     36     int b=e[x].ch[yson^1];
     37     connect(b,y,yson),connect(y,x,yson^1),connect(x,z,zson);
     38     pushup(y),pushup(x);
     39 }
     40 void splay(int x,int goal){
     41     while(e[x].father!=goal){
     42         int y=e[x].father,z=e[y].father;
     43         if(z!=goal)
     44         (identify(x)^identify(y))?rotate(x):rotate(y);
     45         rotate(x);
     46     }
     47     if(goal<=n) root[goal]=x;
     48 }
     49 void push(int x,int k){
     50     int u=root[k],fa=k;
     51     while(u&&e[u].val!=x)
     52         fa=u,u=e[u].ch[x>e[u].val];
     53     u=++cnt;
     54     e[u].size=1,e[u].father=fa;
     55     if(fa>n)
     56         e[fa].ch[x>e[fa].val]=u;
     57     e[u].val=x,e[u].ch[0]=e[u].ch[1]=0;
     58     splay(u,k);    
     59 }
     60 void dfs(int u,int k){
     61     if(e[u].ch[0]) dfs(e[u].ch[0],k);
     62     if(e[u].ch[1]) dfs(e[u].ch[1],k);
     63     push(e[u].val,k);
     64 }
     65 void merge(int a,int b){
     66     int x=ff(a),y=ff(b);
     67     if(x==y) return;
     68     if(e[root[x]].size>e[root[y]].size) swap(x,y);
     69     f[x]=y;
     70     dfs(root[x],y);
     71 }
     72 int get(int x,int k){
     73     int now=root[k];
     74     if(e[now].size<x) return -1;
     75     while(true){
     76         if(e[e[now].ch[0]].size>=x) now=e[now].ch[0];
     77         else if(e[e[now].ch[0]].size+1==x) return e[now].val;
     78         else x-=e[e[now].ch[0]].size+1,now=e[now].ch[1];
     79     }
     80 }
     81 int main(){
     82     //freopen("testdata.in","r",stdin);
     83     n=read(),m=read();
     84     for(int i=1;i<=n;++i) root[i]=i+n,f[i]=i;
     85     cnt=n+n;
     86     for(int i=1;i<=n;++i){
     87         int x=read();
     88         h[x]=i;
     89         e[i+n].val=x,e[i+n].size=1,e[i+n].father=i;    
     90     }
     91     for(int i=1;i<=m;++i){
     92         int x=read(),y=read();
     93         merge(x,y);
     94     }
     95     int t=read();
     96     while(t--){
     97         char s[5];int a,b;
     98         scanf("%s",s);a=read(),b=read();
     99         if(s[0]=='B') merge(a,b);
    100         else{
    101             int ans=get(b,ff(a));
    102             printf("%d
    ",~ans?h[ans]:ans);
    103         }
    104     }
    105     return 0;
    106 }
    深深地明白自己的弱小
  • 相关阅读:
    通达OA二次开发
    通达OA 工作流程 表单设计 高级应用
    PLSQL Develop PlugIn 之脚本自动匹配补全工具CnPlugin
    Oracle性能优化之SQL语句
    Linux重置root密码步骤
    ORA-03113:通信通道的文件结尾解决
    Bat脚本实现MySQL数据库SQL文件备份
    访问父级组件实例
    访问根实例
    插槽其它示例
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9331014.html
Copyright © 2011-2022 走看看