zoukankan      html  css  js  c++  java
  • 洛谷P3224 [HNOI2012]永无乡 线段树合并

    题面

    题解:

    线段树合并的好题。在这题中我们可以用并查集维护连通块,因为要统计第k大,所以还可以用线段树合并来统计子树之间的信息。

    坑点:1:注意炸内存 2:最后输出的是编号,要存起来 3:注意值域线段树中查询第k大的写法

    代码如下:

    #include<cstdio>
    using namespace std;
    const int N=5000005;
    int root[N];
    int n,m;
    int T;
    int lc[N],rc[N];
    int sum[N];
    int fa[N];
    int rev[N];
    int maxx;
    int x,y;
    int o1,o2;
    int k;
    int kkk;
    int val;
    char opt[2];
    int ans;
    int get(int x){//并查集维护连通块 
        if(x!=fa[x]) return fa[x]=get(fa[x]);
    }
    void build(int &rt,int l,int r,int v){
        if(!rt) rt=++T;
        if(l==r){
            sum[rt]++;
            return;
        } 
        int mid=(l+r)>>1;
        if(v<=mid) build(lc[rt],l,mid,v);
        else build(rc[rt],mid+1,r,v);
        sum[rt]=sum[lc[rt]]+sum[rc[rt]];
    }
    int merge(int x,int y){
        if(!x||!y)    return x+y;
        int now=++T;
        sum[now]=sum[x]+sum[y];
        lc[now]=merge(lc[x],lc[y]);
        rc[now]=merge(rc[x],rc[y]);
        return now;
    }
    int query(int rt,int l,int r,int k){//查询第k大 
        if(sum[rt]<k) return 0;
        if(l==r) return l;
        int mid=(l+r)>>1;
        if(sum[lc[rt]]>=k) return query(lc[rt],l,mid,k);
        else return query(rc[rt],mid+1,r,k-sum[lc[rt]]);  
    }
    void united(int x,int y){//合并,并查集和线段树一起合并 
        int f1=get(x);
        int f2=get(y);
        if(f1!=f2) fa[f1]=f2;
        root[f2]=merge(root[f1],root[f2]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=n;i++){
            scanf("%d",&val);
            rev[val]=i;
            build(root[i],1,n,val);
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            united(x,y); 
        } 
        scanf("%d",&k);
        while(k--){
            scanf("%s",opt);
            if(opt[0]=='B'){
                scanf("%d%d",&o1,&o2);
                united(o1,o2);    
            }
            else{
                scanf("%d%d",&o1,&kkk); 
                int ljb=root[get(o1)];
                if(sum[ljb]<kkk) printf("-1
    ");
                else printf("%d
    ",rev[query(ljb,1,n,kkk)]);
            }
        }
        return 0;
    } 
    View Code
  • 相关阅读:
    文件操作一写操作
    文件操作一读操作
    python基础初识
    while循环和格式化输出
    python基础数据类型一(整数类型和布尔值)
    CentOS 6下安装nodejs 0.9.0(转)
    CentOS安装Python教程
    Discuz! X2.5数据库字典(转)
    SQL 语句中的union操作符
    thinkphp空操作和配置文件实现简化路由
  • 原文地址:https://www.cnblogs.com/LJB666/p/11236045.html
Copyright © 2011-2022 走看看