zoukankan      html  css  js  c++  java
  • 【BZOJ2733】永无乡(线段树,并查集)

    【BZOJ2733】永无乡(线段树,并查集)

    题面

    BZOJ

    题解

    线段树合并

    线段树合并是一个很有趣的姿势

    前置技能:动态开点线段树

    具体实现:每次合并两棵线段树的时候,假设叫做(t1,t2),其中要把(t2)合并进(t1)

    假设当前位置(t1)没有节点,则直接把(t2)的这个位置给(t1)(直接接上去就好啦)

    如果(t2)这个位置没有节点,那么直接(return)

    否则,两个位置都有节点,把两个节点的信息合并,然后递归合并左右子树

    简单的代码如下:

    void MergeNode(int &r1,int r2)
    {
    	if(!r1){r1=r2;return;}
    	if(!r2)return;
    	t[r1].v+=t[r2].v;
    	MergeNode(t[r1].ls,t[r2].ls);
    	MergeNode(t[r1].rs,t[r2].rs);
    }
    

    回到这道题目

    对于每一个联通快维护一个值域线段树

    每次在线段树上二分一下第(K)大就好了

    每次修桥相当于合并两棵线段树

    用并查集维护一下联通快就可以啦,多简单

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 120000
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int n,m,Q;
    struct Node
    {
    	int ls,rs;
    	int v;
    }t[MAX<<4];
    int tot;
    int a[MAX];
    void Modify(int &x,int l,int r,int p)
    {
    	if(!x)x=++tot;t[x].v++;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(p<=mid)Modify(t[x].ls,l,mid,p);
    	else Modify(t[x].rs,mid+1,r,p);
    }
    void MergeNode(int &r1,int r2)
    {
    	if(!r1){r1=r2;return;}
    	if(!r2)return;
    	t[r1].v+=t[r2].v;
    	MergeNode(t[r1].ls,t[r2].ls);
    	MergeNode(t[r1].rs,t[r2].rs);
    }
    int Query(int x,int l,int r,int K)
    {
    	if(l==r)return l;
    	int mid=(l+r)>>1;
    	if(K<=t[t[x].ls].v)return Query(t[x].ls,l,mid,K);
    	else return Query(t[x].rs,mid+1,r,K-t[t[x].ls].v);
    }
    int f[MAX],rt[MAX];
    int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;++i)
    	{
    		int x=read();a[x]=i;
    		Modify(rt[f[i]=i],1,n,x);
    	}
    	while(m--)
    	{
    		int a=read(),b=read();
    		a=getf(a);b=getf(b);
    		if(a==b)continue;
    		f[b]=a;
    		MergeNode(rt[a],rt[b]);
    	}
    	Q=read();
    	char opt[5];
    	while(Q--)
    	{
    		scanf("%s",opt);
    		if(opt[0]=='Q')
    		{
    			int x=read(),k=read();
    			x=getf(x);
    			if(t[rt[x]].v<k)puts("-1");
    			else printf("%d
    ",a[Query(rt[x],1,n,k)]);
    		}
    		else
    		{
    			int u=read(),v=read();
    			u=getf(u),v=getf(v);
    			if(u==v)continue;
    			f[v]=u;
    			MergeNode(rt[u],rt[v]);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    CentOS7 运维
    【推荐】开源项目ElasticAmbari助力 ElasticSearch、Kibana、ambari服务高效运维管理
    逆向工程,调试Hello World !程序(更新中)
    校园网内网穿透
    搭建PXE服务及实现安装银河麒麟桌面操作系统
    Linux 的基础知识关于基本操作命令 --- No.3
    Unix/Linux fork前传
    60行C代码实现一个shell
    Linux 的基础知识回顾(安装vmware) ---- No.1 后面都以Centos8 为例
    vue v-bind绑定属性和样式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8559087.html
Copyright © 2011-2022 走看看