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

    题目链接:戳我

    线段树合并(但是这个东西空间到底要开多大呢我不知道,还请dalao指点一二)

    开始每一个点都是一个权值线段树,然后并查集可以维护连通性,如果有路的话,就把他们的祖先连起来就可以了,然后线段树也要合并一下。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n,m,q,cnt;
    int fa[100010],v[100010],rt[1800010],sum[1800010],ls[1800010],rs[1800010],id[100010],cur[100010];
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline void push_up(int x){sum[x]=sum[ls[x]]+sum[rs[x]];}
    inline void insert(int &x,int l,int r,int k)
    {
        if(!x) x=++cnt;
        if(l==r){sum[x]=1;return;}
        int mid=(l+r)>>1;
        if(k<=mid) insert(ls[x],l,mid,k);
        else insert(rs[x],mid+1,r,k);
        push_up(x);
    }
    inline 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]);
        push_up(x);
        return x;
    }
    inline int query(int x,int l,int r,int k)
    {
        if(l==r) return l;
        int mid=(l+r)>>1;
        if(sum[ls[x]]>=k) return query(ls[x],l,mid,k);
        else return query(rs[x],mid+1,r,k-sum[ls[x]]);
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin); 
        freopen("ce.out","w",stdout);
        #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&v[i]),fa[i]=i;
        memcpy(cur,v,sizeof(v));
        sort(&cur[1],&cur[1+n]);
        int cur_cnt=unique(&cur[1],&cur[1+n])-cur-1;
        for(int i=1;i<=n;i++)
            v[i]=lower_bound(&cur[1],&cur[1+cur_cnt],v[i])-cur;
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            int a=find(u),b=find(v);
            if(a!=b) fa[a]=b;
        }
        for(int i=1;i<=n;i++)
        {
            insert(rt[find(i)],1,n,v[i]);
            id[v[i]]=i;
        }
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            char ch[10];
            int x,y;
            scanf("%s%d%d",&ch,&x,&y);
            if(ch[0]=='Q')
            {
                if(sum[rt[find(x)]]<y) printf("-1
    ");
                else printf("%d
    ",id[query(rt[find(x)],1,n,y)]);
            }
            else    
            {
                int a=find(x),b=find(y);
                if(a==b) continue;
                /*if(sum[a]<=sum[b])
                    fa[a]=b,rt[b]=merge(rt[a],rt[b]);
                else   
                    fa[b]=a,rt[a]=merge(rt[b],rt[a]);*/
                fa[a]=b,rt[b]=merge(rt[a],rt[b]);
            }
        }
    }
    

    还有一个问题——难道我写的(注释)不是启发式合并??为什么跑的会更慢呢。。。。。

  • 相关阅读:
    [整理]弦图学习笔记
    [整理]NOI Online 2021第一场题解
    [整理]Pólya 定理入门到入土
    [游记]2021省选抱灵记
    [整理]一些好玩的/板子的动态规划题目
    [整理]网络流随记——终(有关网络流的一些杂项)
    [整理][持续更新]多项式知识点大全(超简洁!)
    [洛谷P4338][题解][ZJOI2018]历史
    [游记]WC2021游记
    Codeforces Round #703 (Div. 2) (A~E)
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10326782.html
Copyright © 2011-2022 走看看