zoukankan      html  css  js  c++  java
  • [BZOJ2733] [HNOI2012]永无乡(并查集 + 线段树合并)

    传送门

    一看到第k大就肯定要想到什么权值线段树,主席树,平衡树之类的

    然后就简单了

    用并查集判断连通,每个节点建立一颗权值线段树,连通的时候直接合并即可

    查询时再二分递归地查找

    时间复杂度好像不是很稳定。。。但hzwer都用这种方法水过。。

    正解好像是平衡树+启发式合并,以后学TT

    #include <cstdio>
    #include <iostream>
    #define N 100001
    
    int n, m, q, cnt;
    int a[N], f[N], sum[N * 20], ls[N * 20], rs[N * 20], root[N], id[N];
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    inline void insert(int &now, int l, int r, int x)
    {
    	now = ++cnt;
    	if(l == r)
    	{
    		sum[now] = 1;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid) insert(ls[now], l, mid, x);
    	else insert(rs[now], mid + 1, r, x);
    	sum[now] = sum[ls[now]] + sum[rs[now]];
    }
    
    inline void merge(int &x, int y)
    {
    	if(!x || !y)
    	{
    		x += y;
    		return;
    	}
    	sum[x] += sum[y];
    	merge(ls[x], ls[y]);
    	merge(rs[x], rs[y]);
    }
    
    inline int query(int now, int l, int r, int x)
    {
    	if(l == r) return l;
    	int mid = (l + r) >> 1;
    	if(sum[ls[now]] >= x)
    		return query(ls[now], l, mid, x);
    	else
    		return query(rs[now], mid + 1, r, x - sum[ls[now]]);
    }
    
    inline int find(int x)
    {
    	return x == f[x] ? x : f[x] = find(f[x]);
    }
    
    int main()
    {
    	int i, x, y;
    	char s[1];
    	n = read();
    	m = read();
    	for(i = 1; i <= n; i++)
    	{
    		f[i] = i;
    		x = read();
    		id[x] = i;
    		insert(root[i], 1, n, x);
    	}
    	for(i = 1; i <= m; i++)
    	{
    		x = find(read());
    		y = find(read());
    		if(x ^ y)
    		{
    			f[y] = x;
    			merge(root[x], root[y]);
    		}
    	}
    	q = read();
    	while(q--)
    	{
    		scanf("%s", s);
    		x = read();
    		y = read();
    		if(s[0] == 'B')
    		{
    			x = find(x);
    			y = find(y);
    			if(x ^ y)
    			{
    				f[y] = x;
    				merge(root[x], root[y]);
    			}
    		}
    		else
    		{
    			x = find(x);
    			if(y > sum[root[x]]) puts("-1");
    			else printf("%d
    ", id[query(root[x], 1, n, y)]);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    免费linux远程主机nitrousIO
    利用PyWapFetion发免费天气短信
    接口中的 sort排序 + md5加密
    即点即改心得
    js判断客户端访问是安卓还是ios
    php将时间戳转换成几小时前的格式封装
    前端请求接口出现的跨域问题
    使用redis技术实现注册登录列表以及关注功能
    windows下的redis安装以及扩展安装
    Yii2 学习心得
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7517730.html
Copyright © 2011-2022 走看看