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

    传送门

    这道题一开始看……能想出来用splay和并查集维护,不过,怎么把两棵splay合并呢……?暴力拆开一个一个合并?

    后来发现真的是这样……不过其实是启发式合并,也就是每次我们合并两棵splay的时候,总是把小的那棵合并到大的那棵上面。这样的话就能保证每个点最多之被合并logn次(别问我为啥,我也不知道)

    具体的操作就是,我们在小的那棵splay上进行dfs,如果这个节点有左/右儿子就向下走,然后无路可走的时候就把它insert到大的那棵splay里面。其他的一切操作都很熟悉。然后每次用并查集维护,注意这次的splay操作都是要从每个节点自己对应的root开始的。

    不知道为什么,我的代码会MLE/RE一个点。所以最后还是抄了yyb大神的代码才过的……

    看一下代码吧(90pts)

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<vector>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define de putchar('#')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const int M = 4000005;
    const int N = 10000005;
    const int INF = 1000000009;
     
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct node
    {
        int ch[2],fa,son,val;
    }t[M];
    
    int n,m,f[M],root[M],tot,idx,num[M],x,y,q;
    char s[10];
    
    int getfa(int x)
    {
        return (x == f[x]) ? x : f[x] = getfa(f[x]);
    }
    
    bool get(int x)
    {
        return t[t[x].fa].ch[1] == x;
    }
    
    void pushup(int x)
    {
        t[x].son = t[t[x].ch[0]].son + t[t[x].ch[1]].son + 1;
    }
    
    void rotate(int x)
    {
        int y = t[x].fa,z = t[y].fa,k = get(x);
        t[z].ch[get(y)] = x,t[x].fa = z;
        t[y].ch[k] = t[x].ch[k^1],t[t[y].ch[k]].fa = y;
        t[x].ch[k^1] = y,t[y].fa = x;
        pushup(x),pushup(y);
    }
    
    void splay(int x,int goal)
    {
        while(t[x].fa != goal)
        {
        int y = t[x].fa,z = t[y].fa;
        if(z != goal) (t[y].ch[0] == x) ^ (t[z].ch[0] == y) ? rotate(x) :rotate(y);
        rotate(x);
        }
        if(goal <= n) root[goal] = x;
    }
    
    void insert(int x,int b)
    {
        int u = root[b],f = b;
        while(u && x != t[u].val) f = u,u = t[u].ch[x > t[u].val];
        u = ++tot;
        if(f > n) t[f].ch[x > t[f].val] = u;
        t[u].son = 1;
        t[u].ch[0] = t[u].ch[1] = 0;
        t[u].fa = f,t[u].val = x;
        splay(u,b);
    }
    
    void dfs(int x,int g)
    {
        if(t[x].ch[0]) dfs(t[x].ch[0],g);
        if(t[x].ch[1]) dfs(t[x].ch[1],g);
        insert(t[x].val,g);
    }
    
    void merge(int x,int y)
    {
        int r1 = getfa(x),r2 = getfa(y);
        if(r1 == r2) return;
        if(t[root[r1]].son > t[root[r2]].son) swap(r1,r2);
        f[r1] = r2;
        dfs(root[r1],r2);
    }
    
    int rk(int x,int k)
    {
        int u = root[x];
        if(t[u].son < k) return -1;
        while(1)
        {
        int y = t[u].ch[0];
        if(t[y].son + 1 < k) k -= (t[y].son + 1),u = t[u].ch[1];
        else if(t[y].son >= k) u = y;
        else return t[u].val;
        }
    }
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,n)
        {
        root[i] = i+n,f[i] = i;
        x = read(),num[x] = i;
        t[i+n].val = x,t[i+n].son = 1,t[i+n].fa = i;
        }
        tot = n << 1;
        rep(i,1,m) x = read(),y = read(),merge(x,y);
        q = read();
        while(q--)
        {
        scanf("%s",s);
        x = read(),y = read();
        if(s[0] == 'B') merge(x,y);
        else
        {
            int g = rk(getfa(x),y);
            (g == -1) ? printf("-1
    ") : printf("%d
    ",num[g]);
        }
        }
        return 0;
    }

    yyb大神的AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define MAX 500000
    inline int read()
    {
        register int x=0,t=1;
        register char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-'){t=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
        return x*t;
    }
    struct Node
    {
        int ch[2];
        int val,ff,size;
    }t[MAX];
    int f[MAX];
    int root[MAX],tot;
    int hh[MAX];
    int N,M;
    int getf(int x)
    {
        return x==f[x]?x:f[x]=getf(f[x]);
    }
    inline void pushup(int x)
    {
        t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
    }
    //1..N分别为N棵splay的0节点
    //每次都对splay进行合并
    inline void rotate(int x)
    {
        int y=t[x].ff;
        int z=t[y].ff;
        int k=t[y].ch[1]==x;
        t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;t[y].ff=x;
        pushup(y);pushup(x);
    }
    inline void splay(int x,int goal)
    {
        while(t[x].ff!=goal)
        {
            int y=t[x].ff,z=t[y].ff;
            if(z!=goal)
                (t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
            rotate(x);
        }
        if(goal<=N)root[goal]=x;//如果是某一个0节点的下方,则更新当前splay的根节点
    }
    inline void insert(int x,int bh)
    {
        int u=root[bh],ff=bh;
        while(u&&t[u].val!=x)
            ff=u,u=t[u].ch[x>t[u].val];
        u=++tot;
        t[u].size=1;
        t[u].ff=ff;
        if(ff>N)
            t[ff].ch[x>t[ff].val]=u;
        t[u].val=x;t[u].ch[0]=t[u].ch[1]=0;
        splay(u,bh);
    }
    void DFS(int u,int kk)//遍历整颗splay
    {
        if(t[u].ch[0])DFS(t[u].ch[0],kk);
        if(t[u].ch[1])DFS(t[u].ch[1],kk);
        insert(t[u].val,kk);//合并到另外一颗splay中
    }
    inline void Merge(int a,int b)
    {
        int x=getf(a),y=getf(b);
        if(x==y)return;//已经在一个集合内
        if(t[root[x]].size>t[root[y]].size)swap(x,y);//强制将小的合并到大的
        f[x]=y;
        DFS(root[x],y);
    }
    int kth(int bh,int k)
    {
        int u=root[bh];
        if(t[u].size<k)return -1;
        while(233)
        {
            if(t[t[u].ch[0]].size+1<k)//在右子树中找
            {
                k-=t[t[u].ch[0]].size+1;
                u=t[u].ch[1];
            }
            else
                if(t[t[u].ch[0]].size>=k)//在左子树中找
                    u=t[u].ch[0];
                else
                    return t[u].val;//当前节点
        }
    }
    int main()
    {
        N=read();M=read();
        for(int i=1;i<=N;++i)root[i]=i+N,f[i]=i;
        tot=N+N;
        for(int i=1;i<=N;++i)
        {
            int x=read();
            hh[x]=i;
            t[i+N].val=x;t[i+N].size=1;t[i+N].ff=i;
        }
        for(int i=1;i<=M;++i)
        {
            int x=read(),y=read();
            Merge(x,y);
        }
        int Q=read();
        while(Q--)
        {
            char ch[3];int a,b;
            scanf("%s",ch);a=read(),b=read();
            if(ch[0]=='B')
            {
                Merge(a,b);
            }
            else
            {
                int ans=kth(getf(a),b);
                printf("%d
    ",ans==-1?ans:hh[ans]);
            }
        }
        return 0;
    }
  • 相关阅读:
    hdu3251 最小割
    2012金华邀请赛解题报告
    Java依照List内存储的对象的某个字段进行排序
    Cocos2d-x移植安卓的笔记
    设计模式------策略模式
    C#实现相似QQ的隐藏浮动窗口、消息闪动
    libiconv字符集转换库在C#中的使用
    poj1564 Sum it up
    Objective-C学习笔记(四)——OC实现最简单的数学运算
    安装配置PhoneGap开发环境(一)
  • 原文地址:https://www.cnblogs.com/captain1/p/9738720.html
Copyright © 2011-2022 走看看