• P3224 [HNOI2012]永无乡


    思路

    并查集+fhqtreap
    合并的时候由于是大小不一,所以不能直接合并
    所以我们就暴力合并喽
    对,就是那种很暴力的把小的往大的身上靠
    他们说是启发式合并
    抄一波博客

    启发式合并
    启发式合并核心思想就一句话:把小集合的合并到大的里。
    启发式合并思想可以放到很多数据结构里,链表、线段树、甚至平衡树都可以。
    考虑时间复杂度,设总共有n个元素,由于每次集合的大小至少翻倍,所以至多会合并lognlogn次,总的复杂度就是O(nlogn)O(nlogn)的
    

    然后不就A了

    错误

    合并写的没毛病呀,最后看着题解改了改就过了?
    明明差不多

    代码

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    #define FOR(i,a,b) for(int i=a;i<=b;++i)
    using namespace std;
    const int maxn=1e5+7;
    int read() {
        int x=0,f=1;char s=getchar();
        for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
        for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
        return x*f;
    }
    int n,m,dsr[maxn],rt[maxn];
    int ch[maxn][2],val[maxn],pri[maxn],siz[maxn];
    int find(int x) {
        return x==rt[x] ? x : rt[x]=find(rt[x]);
    }
    void pushup(int x) {
        siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    }
    int merge(int x,int y) {
        if(!x||!y) return x+y;
        if(pri[x]<pri[y]) {
            ch[x][1]=merge(ch[x][1],y);
            pushup(x);return x;
        } else {
            ch[y][0]=merge(x,ch[y][0]);
            pushup(y);return y;
        }
    }
    void split(int now,int k,int &x,int &y) {
        if(!now) x=y=0;
        else {
            if(val[now]<=k)
                x=now,split(ch[now][1],k,ch[x][1],y);
            else
                y=now,split(ch[now][0],k,x,ch[y][0]);
            pushup(now);
        }
    }
    int k_th(int now,int k) {
        if(siz[now]<k) return -1;
        while(233) {
            if(siz[ch[now][0]]+1==k) return val[now];
            if(siz[ch[now][0]]>=k) now=ch[now][0];
            else k-=siz[ch[now][0]]+1,now=ch[now][1];
        }
    }
    void dfs(int now,int &a) {
        if(!now) return;
        dfs(ch[now][0],a);
        dfs(ch[now][1],a);
        
        ch[now][1]=ch[now][0]=0;
        int x,y;
        split(a,val[now],x,y);
        a=merge(merge(x,now),y);
    }
    void uu(int x,int y) {
        int fx=find(x),fy=find(y);
        if(fx==fy) return;
        if(siz[rt[fx]]<siz[rt[fy]]) swap(fx,fy);
        dfs(rt[fy],rt[fx]);
        rt[fy]=rt[fx];
    }
    int main() {
        srand(time(NULL));
        n=read(),m=read();
        int x,y;
        FOR(i,1,n) {
            val[i]=read();
            rt[i]=dsr[val[i]]=i;
            siz[i]=1;
            pri[i]=rand();
        }
        FOR(i,1,m) x=read(),y=read(),uu(x,y);
        m=read();
        FOR(i,1,m) {
            char s=getchar();
            while(s==' '||s=='
    ') s=getchar();
            x=read(),y=read();
    
            if(s=='Q') {
                x=find(x);
                int tmp=k_th(rt[x],y);
                if(tmp==-1) puts("-1");
                else cout<<dsr[tmp]<<"
    ";
            } else uu(x,y);
        }
        return 0;
    }
    
    
  • 相关阅读:
    浙大版《C语言程序设计(第3版)》题目集 --总结
    | C语言I作业09
    c语言课本及pta作业中运用到的程序思维
    | C语言I作业08
    团队作业(四):描述设计
    实验三《敏捷开发与XP实践》_实验报告
    MyOD(课下作业,选做)
    实验二《面向对象程序设计》_实验报告
    20175226 2018-2019-2《java程序设计》结对编程-四则运算(第二周-阶段总结)
    20175226 类定义
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/10093489.html
Copyright © 2020-2023  润新知