• bzoj 2733 [HNOI2012]永无乡


    线段树合并+并查集

    在每一个联通块上建一个权值线段树

    每次用并查集判断维护,线段树合并即可

    相当于每一次询问都在这个联通块一个线段树上问区间第k小

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2*1e5+100;
    int n,m,q,rk[MAXN],fa[MAXN],root[MAXN];
    int t,f[MAXN];
    struct node
    {
        int lc,rc,sum;
    }sh[MAXN*15];
    int getfather(int x)//并查集
    {
        if (fa[x]==x)
          return x;
        fa[x]=getfather(fa[x]);
        return fa[x];
    }
    void insert(int &x,int l,int r,int where)
    {
        if (!x)
        {
            t++;
            x=t;
        }
        if (l==r)
        {
            sh[x].sum=1;
            return;
        }
        int mid;
        mid=(l+r)/2;
        if (where<=mid)
          insert(sh[x].lc,l,mid,where);
        else
          insert(sh[x].rc,mid+1,r,where);
        sh[x].sum=sh[sh[x].lc].sum+sh[sh[x].rc].sum;
    }
    int merge(int u,int v)//线段树合并
    {
        if (!u)
          return v;
        if (!v)
          return u;
        sh[u].lc=merge(sh[u].lc,sh[v].lc);
        sh[u].rc=merge(sh[u].rc,sh[v].rc);
        sh[u].sum=sh[sh[u].lc].sum+sh[sh[u].rc].sum;
        return u;
    }
    int query(int x,int l,int r,int k)
    {
        if (l==r)
          return l;
        int mid;
        mid=(l+r)/2;
        if (sh[sh[x].lc].sum>=k)
          return query(sh[x].lc,l,mid,k);
        else
          return query(sh[x].rc,mid+1,r,k-sh[sh[x].lc].sum);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&rk[i]);
            f[rk[i]]=i;
            fa[i]=i;
        }
        for (int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if (getfather(u)!=getfather(v))
            {
                fa[getfather(u)]=getfather(v);
            }
        }
        for (int i=1;i<=n;i++)
        {
            insert(root[getfather(i)],1,n,rk[i]);//联通块上建线段树
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++)
        {
            int a,b;
            char ch[10];
            scanf("%s%d%d",ch,&a,&b);
            if (ch[0]=='Q')
            {
                int father;
                father=getfather(a);
                if (sh[root[father]].sum<b)
                {
                    printf("-1
    ");
                }
                else
                {
                    printf("%d
    ",f[query(root[father],1,n,b)]);//找第k小数
                }
            }
            else
            {
                if (getfather(a)!=getfather(b))
                {
                    root[getfather(a)]=merge(root[getfather(b)],root[getfather(a)]);
                    fa[getfather(a)]=getfather(b);//并查集维护
                }
            }
        }
    }
  • 相关阅读:
    午餐
    Page Visibility API 页面是否获取焦点 Event: visibilitychange
    js dom 观察者属性 MutationObserver
    js substr和substring
    萌新 学习 vuex
    font-awesome图标转为图片
    如何用 CSS Animations 实现滑动图片展现文字的效果
    CSS3的变形、过渡、动画、关联属性
    用户网站访问速度慢详解
    CSS尺寸单位
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/10686006.html
Copyright © 2020-2023  润新知