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

    Description

    永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。

    Solution

    初学线段树合并,此题中开一棵值域,由于此题中每一个节点在遍历时只会被合并一次,也就是说只有一次是被 (O(log)) 的遍历到,所以均摊复杂度 (O(nlogn))

    线段树合并模板:

    int merge(int x,int y){
       if(!x)return y;if(!y)return x;
       t[x].ls=merge(t[x].ls,t[y].ls);
       t[x].rs=merge(t[x].rs,t[y].rs);
       t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
       return x;
    }
    
    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=100005;
    struct node{
       int ls,rs,sum;
    }t[N*20];
    int n,m,Q,root[N],val[N],b[N],num=0,fa[N],cnt=0,totnode=0;
    char s[3];int id[N];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void ins(int &rt,int l,int r,int sa){
       if(!rt)rt=++totnode;
       if(l==r){t[rt].sum++;return ;}
       int mid=(l+r)>>1;
       if(sa<=mid)ins(t[rt].ls,l,mid,sa);
       else ins(t[rt].rs,mid+1,r,sa);
       t[rt].sum=t[t[rt].ls].sum+t[t[rt].rs].sum;
    }
    int query(int rt,int k,int l,int r){
       if(l==r)return l;
       int mid=(l+r)>>1;
       if(t[t[rt].ls].sum>=k)return query(t[rt].ls,k,l,mid);
       return query(t[rt].rs,k-t[t[rt].ls].sum,mid+1,r);
    }
    int merge(int x,int y){
       if(!x)return y;if(!y)return x;
       t[x].ls=merge(t[x].ls,t[y].ls);
       t[x].rs=merge(t[x].rs,t[y].rs);
       t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
       return x;
    }
    void work()
    {
       int x,y;
       scanf("%d%d",&n,&m);
       for(int i=1;i<=n;i++)scanf("%d",&val[i]),b[++num]=val[i],fa[i]=i;
       sort(b+1,b+num+1);
       for(int i=1;i<=n;i++)val[i]=lower_bound(b+1,b+num+1,val[i])-b;
       for(int i=1;i<=n;i++)ins(root[i],1,n,val[i]),id[val[i]]=i;
       for(int i=1;i<=m;i++){
          scanf("%d%d",&x,&y);
          if(find(x)!=find(y)){
             root[find(x)]=merge(root[find(x)],root[find(y)]);
             fa[find(y)]=find(x);
          }
       }
       scanf("%d",&Q);
       while(Q--){
          scanf("%s%d%d",s,&x,&y);
          if(s[0]=='Q'){
             if(t[root[find(x)]].sum<y)puts("-1");
             else printf("%d
    ",id[query(root[find(x)],y,1,n)]);
          }
          else {
             root[find(x)]=merge(root[find(x)],root[find(y)]);
             fa[find(y)]=find(x);
          }
       }
    }
    
    int main(){work();return 0;}
    
    
  • 相关阅读:
    JavaScript对象编程-第3章
    JavaScript对象编程-第3章
    JavaScript基础-第2章
    JavaScript基础-第2章
    JavaScript基础-第2章
    第十八节:详解Java抽象类和接口的区别
    第十八节:详解Java抽象类和接口的区别
    第十八节:详解Java抽象类和接口的区别
    JavaScript概述-第1章
    JavaScript概述-第1章
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7662003.html
Copyright © 2011-2022 走看看