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

    题意

    给出n个岛屿和每个岛屿的重要度排名,初始岛屿间有m座桥,有两种操作:询问与x相连通的岛屿中重要度排名第k小的岛屿编号,不存在输出-1;给x,y岛屿之间建桥。

    对于 100% 的数据 n100000,mn,q300000

    题解

    需要一个可以查询第k小的数据结构,可以使用splay。

    考虑怎么合并:暴力就好了。将小的splay一个一个插入大的splay,每个点最多被合并log次。

    现在考虑如何维护多个splay,经过sxk大佬的指点:一开始建n个splay,用root[]记录每个splay的根,然后函数传参的时候就记录操作在哪一个splay就好。

    然后连通性的话不想写并查集,于是想到记录每个点在哪颗splay,判断就直接看root[belong[x]]是否相同(而且o(1)),belong在插入时维护就好。

    在遍历插入时一定是最后插入,因为你插入时会把信息重新清一遍,所以相当于直接把原来他所在的splay的后面节点抛弃了,然后可能就会从新的splay里面遍历,就会GG。

    这道题也不用插入最值(虽然我一直不知道最值有啥用)

    对于他们再用一个数组记录排名为i的岛屿的编号有点没看懂,因为如果你最初节点编号就是岛屿编号而且之后节点编号又不变的话,完全没必要记录,直接输出节点编号就好了。

    然后合并那里因为判断了splay大小涉及swap,所以后面的splay编号就不能写成belong[x],具体看代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    int n,m,q;
    int root[maxn],belong[maxn];//root每颗splay的根,belong 每个点是哪颗splay
    struct Splay{
      int fa,size,val,s[2];
    }tr[maxn];
    
    template<class T>inline void read(T &x) {
      x=0;char ch=getchar();
      while(!isdigit(ch)) ch=getchar();
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    void update(int x){
      tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+1;
    }
    
    void connect(int x,int y,int d){
      tr[x].fa=y;
      tr[y].s[d]=x;
    }
    
    int get(int x){
      return tr[tr[x].fa].s[1]==x;
    }
    
    void rotate(int x){
      int f=tr[x].fa,ff=tr[f].fa;
      int d1=get(x),d2=get(f);
      int cs=tr[x].s[d1^1];
      connect(x,ff,d2);
      connect(f,x,d1^1);
      connect(cs,f,d1);
      update(f);
      update(x);
    }
    
    void splay(int x,int go,int id){
      if(go==root[id]) root[id]=x;
      go=tr[go].fa;
      while(tr[x].fa!=go){
        int f=tr[x].fa;
        if(tr[f].fa==go) rotate(x);
        else if(get(x)==get(f)) {rotate(f);rotate(x);}
        else {rotate(x);rotate(x);}
      }
    }
    
    void insert(int id,int val,int x){//插入第几颗splay,值,编号
      int now=root[id];
      belong[x]=id;
      if(!now){
        root[id]=x;
        tr[x].size=1;
        tr[x].val=val;
        return ;
      }
      while(324){
        tr[now].size++;
        int o=val>tr[now].val;
        if(!tr[now].s[o]){
          tr[x]=(Splay){now,1,val,{0,0}};
          tr[now].s[o]=x;
          break;
        }
        now=tr[now].s[o];
      }
      splay(x,root[id],id);
    }
    
    void dfs(int x,int y){//y节点插入第x个splay
      //printf("--%d--
    ",y);
      if(tr[y].s[0]) dfs(x,tr[y].s[0]);
      if(tr[y].s[1]) dfs(x,tr[y].s[1]);
      insert(x,tr[y].val,y);
    }
    
    void merge(){
      int x,y;
      read(x);read(y);
      int dx=root[belong[x]],dy=root[belong[y]];
      if(dx==dy) return ;
      if(tr[dx].size<tr[dy].size) swap(dx,dy);
      //putchar(10);
      //printf("%d %d %d--------
    ",belong[x],dx,dy);
      dfs(belong[dx],dy);//不能写belong[x],因为上面可能swap了
    }
    
    int query(int now,int k){
      while(324){
        if(tr[tr[now].s[0]].size>=k) {now=tr[now].s[0];continue;}
        k-=tr[tr[now].s[0]].size;
        if(k==1) break;
        k--;
        now=tr[now].s[1];
      }
      splay(now,root[belong[now]],belong[now]);
      return now;
    }
    
    int main(){
      read(n);read(m);
      for(int i=1;i<=n;i++){
        int x;read(x);
        insert(i,x,i);
      }
      //for(int i=1;i<=n;i++) printf("%d ",belong[i]);
      //putchar(10);
      for(int i=1;i<=m;i++) merge();
      read(q);
      for(int i=1;i<=q;i++){
        char op[2];
        scanf("%s",op);
        if(op[0]=='B') merge();
        else {
          int x,k;
          read(x);read(k);
          int dx=root[belong[x]];
          if(tr[dx].size<k) printf("-1
    ");
          else printf("%d
    ",query(dx,k));
        }
      }
    }
    View Code
  • 相关阅读:
    lua时间戳和日期转换及踩坑【转】
    Js正则表达式验证输入是否有特殊字符【转】
    PHP数据类型转换【转】
    JavaScript indexOf() 方法
    CSS文本下划线 删除线 上划线【转】
    PHP中把stdClass Object转array的几个方法【转】
    2020软件工程作业02
    2020软件工程作业01
    2020 CCPC Wannafly Winter Camp Day1-F-乘法
    牛客-装货物
  • 原文地址:https://www.cnblogs.com/sto324/p/11302465.html
Copyright © 2011-2022 走看看