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

    初始给定一个n个点m条边的无向图,q次操作,每次要么新增一条边,要么查询与某个点相连的所有点里点权第K小的点的编号。

    查询联通分量容易想到并查集,查询第K大需要用平衡树,容易想到每个联通分量维护一棵平衡树,

    每次新增加一条边对联通分量的影响就是合并两颗平衡树,为了保障复杂度正确,我们采用启发式合并,每次把小的联通分量的每个值暴力插到大的联通分量中,

    简单来看,启发式合并一次,容量至少对小的联通分量来说是翻倍,再加上插入平衡树的均摊复杂度是O(logn)的,乍一看复杂度是O(nlog^2n)的

    (不过camp讲课的时候说,把小的Splay的每个数值从小到大插入到大的Splay中,时间复杂度是O(nlogn)的,证明需要用到Dynamic Finger Theorem)

    然后,貌似就做完了

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=5e5;
    const int INF=0x3f3f3f3f;
    typedef long long ll;
    struct Splay
    {
        int ch[2];
        int fa;
        int cnt,val,sz;
    }b[maxn+5];
    int father[maxn+5];
    int tot=0,root[maxn+5];
    inline int newNode(int fa,int val)
    {
        int p=++tot;
        b[p].fa=fa;
        b[p].val=val;
        b[p].cnt=b[p].sz=1;
        if (fa) b[fa].ch[b[fa].val<val]=p;
        b[p].ch[0]=b[p].ch[1]=0;
        return p;
    }
    inline int checkR(int p)
    {
        return b[b[p].fa].ch[1]==p;
    }
    inline void pushup(int p)
    {
        b[p].sz=b[p].cnt;
        if (b[p].ch[0]) b[p].sz+=b[b[p].ch[0]].sz;
        if (b[p].ch[1]) b[p].sz+=b[b[p].ch[1]].sz;
    }
    inline void RotateNode(int p)
    {
        int f=b[p].fa,ff=b[f].fa,w=checkR(p);
        b[f].ch[w]=b[p].ch[w^1]; b[b[f].ch[w]].fa=f;
        b[f].fa=p; b[p].ch[w^1]=f;
        b[p].fa=ff;
        if (ff) b[ff].ch[b[ff].ch[1]==f]=p;
        pushup(f); pushup(p);
    }
    inline void SplayNode(int p,int goal,int q) //把p旋转为goal的儿子
    {
        while (b[p].fa!=goal) {
            int f=b[p].fa;
            int ff=b[f].fa;
            if (ff!=goal) {
                if (checkR(p)==checkR(f)) RotateNode(f);
                else RotateNode(p);
            }
            RotateNode(p);
        }
        if (goal==0) root[q]=p;
    }
    inline void InsertNode(int val,int q)
    {
        int u=root[q],fa=0;
        while (u) {
            if (b[u].val==val) {
                b[u].cnt++; pushup(u); SplayNode(u,0,q); return ;
            }
            fa=u;
            u=b[u].ch[b[u].val<val];
        }
        u=newNode(fa,val); SplayNode(u,0,q);
    }
    inline int getVal(int rk,int q)
    {
        int u=root[q];
        while (u) {
            if (rk<=b[b[u].ch[0]].sz) u=b[u].ch[0];
            else if (rk<=b[b[u].ch[0]].sz+b[u].cnt) {
                SplayNode(u,0,q);
                break;
            }
            else {
                rk-=(b[b[u].ch[0]].sz+b[u].cnt);
                u=b[u].ch[1];
            }
        }
        return b[u].val;
    }
    int _find(int x)
    {
        if (x==father[x]) return x;
        father[x]=_find(father[x]);
        return father[x];
    }
    void dfs(int p,int to)
    {
        if (b[p].ch[0]) dfs(b[p].ch[0],to);
        InsertNode(b[p].val,to);
        if (b[p].ch[1]) dfs(b[p].ch[1],to);
    }
    void dfsSplay(int u)
    {
        printf("%d ",b[u].val);
        if (b[u].ch[0]) dfsSplay(b[u].ch[0]);
        if (b[u].ch[1]) dfsSplay(b[u].ch[1]);
    }
    void _merge(int u,int v)
    {
        u=_find(u); v=_find(v);
        if (u==v) return ;
        if (b[root[u]].sz>b[root[v]].sz) swap(u,v);
        father[u]=v;
        dfs(root[u],v);
    }
    char s[10];
    int n,m,q,x,y;
    int a[maxn+5],mp[maxn+5];
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) father[i]=i;
        for (int i=1;i<=n;i++) {
            scanf("%d",&a[i]); mp[a[i]]=i;
        }
        for (int i=1;i<=n;i++) InsertNode(a[i],i);
        //for (int i=1;i<=n;i++) printf("%d %d %d
    ",i,root[i],b[root[i]].val);
        while (m--) {
            scanf("%d%d",&x,&y);
            _merge(x,y);
        }
        scanf("%d",&q);
        while (q--) {
            scanf("%s",s);
            scanf("%d%d",&x,&y);
            if (s[0]=='B') {
                _merge(x,y);
            }
            else {
                int u=_find(x);
                if (b[root[u]].sz<y) printf("-1
    ");
                else printf("%d
    ",mp[getVal(y,u)]);
            }
        }
        return 0;
    }
  • 相关阅读:
    SharePoint 2010 User Profile Sync Service自动停止
    如何区别多个svchost.exe?
    Log Parser分析IIS log的一个简单例子
    Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
    Windows中右键点击文件夹, 结果找不到共享选项卡, 怎么办?
    介绍SOS中的SaveModule命令
    SharePoint中Draft版本的文档不会收到document added的Alert Email
    和我一起学Windows Workflow Foundation(1)创建和调试一个WF实例
    门户网站
    C#基础—— check、lock、using语句归纳
  • 原文地址:https://www.cnblogs.com/xyw5vplus1/p/12229769.html
Copyright © 2011-2022 走看看