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;
    }
    
    
  • 相关阅读:
    h.264宏块与子宏块类型
    h.264语法结构分析
    [傅里叶变换及其应用学习笔记] 关于任何信号都能表现成傅里叶级数形式的推导
    [傅里叶变换及其应用学习笔记] 课程概览
    [傅里叶变换及其应用学习笔记] 三十. 拉东变换
    [傅里叶变换及其应用学习笔记] 二十九. 高维Ш函数修改版
    后端解决 微信H5支付 商户参数格式错误 方法
    PhpStorm一次性折叠所有函数或者方法
    js生成的cookie在yii2中获取不到的解决办法
    Android webview 调起H5微信支付
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8559087.html
Copyright © 2011-2022 走看看