• 2733. [HNOI2012]永无乡【平衡树-splay】


    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

    tmd手残把rotate写错了……
    中间将一个splay的点插入到另一个splay中忘了把插入的点clear……
    什么鬼啊一个启发式合并的模板题为什么让我做成这样……
    累觉不爱

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #define N (100000+100) 
      5 using namespace std;
      6 int n,m,p;
      7 int Root[N],num[N];
      8 int Val[N],Size[N],Father[N],Son[N][2];
      9 
     10 int Get(int x) {return Son[Father[x]][1]==x;}
     11 void Update(int x) {Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;}
     12 void Clear(int x) {num[x]=Size[x]=Father[x]=Son[x][0]=Son[x][1]=0;}
     13 void Rotate(int x)
     14 {
     15     int wh=Get(x);
     16     int fa=Father[x],fafa=Father[fa];
     17     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
     18     Father[fa]=x; Son[fa][wh]=Son[x][wh^1];
     19     if (Son[fa][wh]) Father[Son[fa][wh]]=fa; 
     20     Father[x]=fafa; Son[x][wh^1]=fa;
     21     Update(fa); Update(x); 
     22 }
     23 
     24 void Splay(int x)
     25 {
     26     for (int fa;fa=Father[x];Rotate(x))
     27         if (Father[fa])
     28             Rotate(Get(x)==Get(fa)?fa:x);
     29     Root[num[x]]=x;
     30 }
     31 
     32 void Insert(int x,int y)//insert x to y
     33 {
     34     int now=Root[num[y]],fa=0;
     35     while (1)
     36     {
     37         fa=now,now=Son[now][Val[x]>Val[now]];
     38         if (now==0)
     39         {
     40             Father[x]=fa;
     41             Son[fa][Val[x]>Val[fa]]=x;
     42             Size[x]=1;
     43             num[x]=num[y];
     44             Update(fa);
     45             Splay(x);
     46             return;
     47         }
     48     }
     49 }
     50 
     51 void Dfs(int x,int y)
     52 {
     53     if (Son[x][0]) Dfs(Son[x][0],y);
     54     if (Son[x][1]) Dfs(Son[x][1],y);
     55     Clear(x); 
     56     Insert(x,y);
     57 }
     58 
     59 void Merge(int x,int y)
     60 {
     61     if (Size[x]>Size[y]) swap(x,y);
     62     Dfs(x,y); 
     63 }
     64 
     65 int Findx(int now,int x)
     66 {
     67     while (1)
     68         if (x<=Size[Son[now][0]])
     69             now=Son[now][0];
     70         else
     71         {
     72             x-=Size[Son[now][0]];
     73             if (x==1)
     74             {
     75                 Splay(now);
     76                 return now;
     77             }
     78             x--;
     79             now=Son[now][1];
     80         }
     81 }
     82 
     83 int main()
     84 {
     85     char opt[5];
     86     int x,y;
     87     scanf("%d%d",&n,&m);
     88     for (int i=1;i<=n;++i)
     89     {
     90         scanf("%d",&Val[i]);
     91         Root[i]=num[i]=i;
     92         Size[i]=1; 
     93     }
     94     //num表示每个点属于的树的标号,Root表示对于标号树的根 
     95     for (int i=1;i<=m;++i)
     96     {
     97         scanf("%d%d",&x,&y);
     98         if (num[x]!=num[y])
     99             Merge(Root[num[x]],Root[num[y]]);
    100     }
    101     scanf("%d",&p);
    102     for (int i=1;i<=p;++i) 
    103     {
    104         scanf("%s%d%d",opt,&x,&y);
    105         if (opt[0]=='Q') printf("%d
    ",Size[Root[num[x]]]>=y?Findx(Root[num[x]],y):-1);
    106         if (opt[0]=='B' && num[x]!=num[y]) Merge(Root[num[x]],Root[num[y]]);
    107      }
    108 }
  • 相关阅读:
    斗鱼的sidebar的实现简陋的demo
    angular JS中使用jquery datatable添加checkbox点击事件
    angular JS中使用jquery datatable添加ng-click事件
    Redis 中文文档
    操作word的
    Redis作为消息队列服务场景应用案例(入队和出队)
    nopcommerce 商城案例
    net 将手机号码中间的数字替换成星号
    V5客服
    EF 数据库迁移(Migration)
  • 原文地址:https://www.cnblogs.com/refun/p/8680752.html
Copyright © 2020-2023  润新知