zoukankan      html  css  js  c++  java
  • Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

    2733: [HNOI2012]永无乡

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 3955  Solved: 2112
    [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
      这道题当时第一眼觉得像是图论tarjan题,然后看到了求排名的操作,这就不得不考虑平衡树了,由于平衡树我只会SPLAY,不会无旋TREAP所以我就只讲SPLAY的了。
      这道题想到平衡树后就开始想合并操作,如果暴力合并最坏貌似是炸翻天的,一开始以为有什么神奇的打法,比如区间插入还自带平衡的黑科技之类的,结果同桌告诉我是启发式合并。所谓启发式合并就是暴力合并,只是有一个几乎所有人都想的到的剪枝,让小项去合并大项,时间自然会小不少。
      所以对于每一次合并我们只是dfs一边当前的小子树,然后就暴力合并就好了,其他操作照常。
      1 #pragma GCC optimze("O3")
      2 #include<iostream>
      3 #include<cstdlib>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<queue>
      7 #include<algorithm>
      8 #include<cmath>
      9 #include<map>
     10 #define N 100004
     11 using namespace std;
     12 int n,m,q,f[N],fa[N],size[N],ch[N][2],data[N];
     13 int find(int x)
     14 {
     15     if(f[x]==x)return x;
     16     return f[x]=find(f[x]);
     17 }
     18 bool get(int x)
     19 {
     20     return x==ch[fa[x]][1];
     21 }
     22 void update(int x)
     23 {
     24     if(x)
     25     {
     26         size[x]=1;
     27         if(ch[x][0]) size[x]+=size[ch[x][0]];
     28         if(ch[x][1]) size[x]+=size[ch[x][1]];
     29     }
     30 }
     31 void rotate(int x)
     32 {
     33     int faa=fa[x],ffa=fa[fa[x]];
     34     int op=get(x);
     35     ch[faa][op]=ch[x][op^1];
     36     fa[ch[faa][op]]=faa;
     37     ch[x][op^1]=faa;
     38     fa[faa]=x;
     39     fa[x]=ffa;
     40     if(ffa)ch[ffa][ch[ffa][1]==faa]=x;
     41     update(faa);
     42     update(x);
     43     return;
     44 }
     45 void splay(int x)
     46 {
     47     for(int ff;ff=fa[x];rotate(x))
     48     {
     49         if(fa[ff])
     50             rotate((get(x)==get(ff))?ff:x);
     51     }
     52     return;
     53 }
     54 int lart;
     55 void insert(int x,int now,int faa)
     56 {
     57  
     58     if(now==0)
     59     {
     60         fa[x]=faa;
     61         if(data[x]<data[faa]) ch[faa][0]=x;
     62         else ch[faa][1]=x;
     63         splay(x);
     64         lart=x;
     65         return;
     66     }
     67     if(data[x]<data[now])insert(x,ch[now][0],now);
     68     else insert(x,ch[now][1],now);
     69 }
     70 void dfs(int x,int y)
     71 {
     72     int le=ch[x][0],ri=ch[x][1];
     73     ch[x][0]=ch[x][1]=0;
     74     insert(x,y,0);
     75     if(le)dfs(le,lart);
     76     if(ri)dfs(ri,lart);
     77 }
     78 int get_rank(int x,int la)
     79 {
     80     if(la==size[ch[x][0]]+1)
     81         return x;
     82     if(la<=size[ch[x][0]])
     83         return get_rank(ch[x][0],la);
     84     else
     85         return get_rank(ch[x][1],la-size[ch[x][0]]-1);
     86 }
     87 int main()
     88 {
     89     scanf("%d%d",&n,&m);
     90     for(int i=1;i<=n;i++)
     91     {
     92         scanf("%d",&data[i]);
     93         f[i]=i;size[i]=1;
     94     }
     95     for(int i=1;i<=m;i++)
     96     {
     97         int x,y;
     98         scanf("%d%d",&x,&y);
     99         int aa=find(x),bb=find(y);
    100         if(aa==bb)continue;
    101         f[aa]=bb;
    102         splay(x),splay(y);
    103         if(size[x]>size[y])
    104             dfs(y,x);
    105         else
    106             dfs(x,y);
    107     }
    108     scanf("%d",&q);
    109     char b[10];
    110     for(int i=1;i<=q;i++)
    111     {
    112         scanf("%s",b);
    113         int x,y;
    114         scanf("%d%d",&x,&y);
    115         if(b[0]=='B')
    116         {
    117             int aa=find(x),bb=find(y);
    118             if(aa==bb)continue;
    119             f[aa]=bb;
    120             splay(x),splay(y);
    121             if(size[x]>size[y])
    122                 dfs(y,x);
    123             else
    124                 dfs(x,y);
    125         }
    126         else
    127         {
    128             splay(x);
    129             if(size[x]<y)printf("-1
    ");
    130             else
    131             {
    132                 printf("%d
    ",get_rank(x,y));
    133             }
    134         }
    135     }
    136     return 0;
    137 }
    View Code
  • 相关阅读:
    iOS应用内支付(内购)的个人开发过程及坑!
    AJAX实现仿Google Suggest效果
    jquery的show/hide性能测试
    如何做到尽可能不使用庞大的jQuery
    CSS3 transition规范的实际使用经验
    jQuery提升性能技巧及个人总结
    使用CSS3实现超炫的Loading(加载)动画效果
    一个有趣的Ajax Hack示范
    使用ajax技术无刷新动态调用股票信息
    将Asp.Net页面输出到EXCEL里去
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7587586.html
Copyright © 2011-2022 走看看