• BZOJ- 2733: 永无乡 (并查集&线段树合并)


    题意:给定N个节点,K次操作,操作有两种,1是合并两个集合,2是求某个集合的第K大(从小到大排序)。

    思路:合并只要启发式即可。此题可以用线段树,保存1到N的排序的出现次数和。 复杂度O(NlogN)。想象一下,当其中一棵树节点少的时候,复杂度是O(logN)的,次数不超过N次;当两棵树的节点都蛮多的时候,复杂度是O(N)的,但是这样的合并能使得集合变得很大,显然这样的合并次数非常少,小于logN次。

    所以合并线段树的总复杂度就算O(NlogN),每次询问K大的操作是线段树常规操作,单词复杂度是logN的

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=4000010;
    int rt[maxn],ls[maxn],rs[maxn],fa[maxn],cnt;
    int a[maxn],id[maxn],sum[maxn];
    int find(int u){
        if(fa[u]!=u) fa[u]=find(fa[u]);
        return fa[u];
    }
    void insert(int &Now,int L,int R,int pos)
    {
        if(!Now) Now=++cnt; sum[Now]++;
        if(L==R) return ;int Mid=(L+R)>>1;
        if(pos<=Mid) insert(ls[Now],L,Mid,pos);
        else insert(rs[Now],Mid+1,R,pos);
    }
    int merge(int x,int y){
        if(!x) return y;
        if(!y) return x;
        ls[x]=merge(ls[x],ls[y]);
        rs[x]=merge(rs[x],rs[y]);
        sum[x]=sum[ls[x]]+sum[rs[x]];
        return x;
    }
    int query(int x,int L,int R,int num){
        if(L==R) return L; int Mid=(L+R)>>1;
        if(sum[ls[x]]>=num) return query(ls[x],L,Mid,num);
        return query(rs[x],Mid+1,R,num-sum[ls[x]]);
    }
    int main()
    {
        int N,M,K,u,v; char opt[4];
        scanf("%d%d",&N,&M);
        rep(i,1,N) scanf("%d",&a[i]),id[a[i]]=i;
        rep(i,1,N) fa[i]=i;
        rep(i,1,M) {
            scanf("%d%d",&u,&v);
            int p=find(u),q=find(v);
            if(p!=q) fa[p]=q;
        }
        scanf("%d",&K);
        rep(i,1,N) insert(rt[find(i)],1,N,a[i]);
        rep(i,1,K){
            scanf("%s%d%d",opt,&u,&v);
            if(opt[0]=='B'){
               int p=find(u),q=find(v);
               if(p!=q){
                  fa[q]=p;
                  rt[p]=merge(rt[p],rt[q]);
               }
            }
            else {
                int p=find(u);
                if(sum[rt[p]]<v) puts("-1");
                else printf("%d
    ",id[query(rt[p],1,N,v)]);
            }
        }
        return 0;
    }
  • 相关阅读:
    C#接口入门学习
    消息队列接收时报错:对消息队列系统的访问被拒绝
    给某做测试的好友的建议
    在不同的Sql Server 数据库服务器(不同机器)导数据。
    如何让开发人员更好测试?
    存储过程初探
    语音报警.NET开发初探
    vs2010下Siverlight开发环境安装
    C# HttpWebRequest 从google服务器获取google的PageRank PR值
    创建进程API CreateProcess Demo
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9679214.html
Copyright © 2020-2023  润新知