ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

1063. 永无乡

2022-07-09 23:31:46  阅读:150  来源: 互联网

标签:sz int 1063 tr 节点 splay root 永无


题目链接

1063. 永无乡

永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示。

某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。

如果从岛 \(a\) 出发经过若干座(含 \(0\) 座)桥可以到达岛 \(b\) ,则称岛 \(a\) 和岛 \(b\) 是连通的。

现在有两种操作:

  • \(B\ x\ y\) 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。

  • \(Q\ x\ k\) 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪座,请你输出那个岛的编号。

输入格式

第一行是用空格隔开的两个正整数 \(n\) 和 \(m\) ,分别表示岛的个数以及一开始存在的桥数。

接下来的一行是用空格隔开的 \(n\) 个数,依次描述从岛 \(1\) 到岛 \(n\) 的重要度排名。

随后的 \(m\) 行每行是用空格隔开的两个正整数 \(a_i\) 和 \(b_i\) ,表示一开始就存在一座连接岛 \(a_i\) 和岛 \(b_i\) 的桥。

后面剩下的部分描述操作,该部分的第一行是一个正整数 \(q\) ,表示一共有 \(q\) 个操作,接下来的 \(q\) 行依次描述每个操作,操作的格式如上所述,以大写字母 \(Q\) 或 \(B\) 开始,后面跟两个不超过 \(n\) 的正整数,字母与数字以及两个数字之间用空格隔开。

输出格式

对于每个 \(Q\ x\ k\) 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。

如果该岛屿不存在,则输出 \(-1\)。

数据范围

对于 \(20%\) 的数据 \(n \le 1000, q \le 1000\),
对于 \(100%\) 的数据 \(n \le 100000, m \le n, q \le 300000\)

输入样例:

5 1
4 3 2 5 1
1 2
7
Q 3 2
Q 2 1
B 2 3
B 1 5
Q 2 1
Q 2 4
Q 2 3

输出样例:

-1
2
5
1
2

解题思路

splay,启发式合并

建立 \(n\) 棵 \(splay\) 树,合并时用并查集维护信息,当要合并两棵 \(splay\) 树时,直接暴力将一棵 \(splay\) 树插入到另外一棵 \(splay\) 树上,可采用启发式合并,即将更小的 \(splay\) 树合并到更大的 \(splay\) 树上。注意:当合并时,将节点一个一个插入 \(splay\) 树中时,完全可以利用该节点的状态编号而不必生成新的节点编号,另外 \(splay\) 树中的状态节点编号与中序遍历表示的值的编号是相等的,且所有操作没有改变其对应的关系,所以可以直接利用状态节点编号返回查询的信息
另外,简单说下并查集中的节点与 \(splay\) 树中的节点的联系:并查集中节点表示一棵 \(splay\) 树,并查集的根节点 \(i\) 用 \(root[i]\) 表示 \(splay\) 树中的根节点编号,注意,\(i\neq root[i]\),在执行 \(splay(x,k)\) 操作时,并查集的 \(i\) 是不会变化的,而 \(splay\) 的根节点时刻发生变化,当节点的编号不会发现生变化,即 \(splay\) 的节点编号依然与中序遍历的编号对应

  • 时间复杂度:\(O(n+qlog^2n)\)

代码

// Problem: 永无乡
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1065/
// Memory Limit: 128 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5;
int n,m,root[N],fa[N],a,b;
struct Tr
{
	int s[2],p,v,sz;
	void init(int _p,int _v)
	{
		p=_p,v=_v;
		sz=1;
	}
}tr[N];
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void pushup(int u)
{
	tr[u].sz=tr[tr[u].s[0]].sz+tr[tr[u].s[1]].sz+1;
}
void rotate(int x)
{
	int y=tr[x].p,z=tr[y].p;
	int k=tr[y].s[1]==x;
	tr[z].s[tr[z].s[1]==y]=x,tr[x].p=z;
	tr[y].s[k]=tr[x].s[k^1],tr[tr[x].s[k^1]].p=y;
	tr[x].s[k^1]=y,tr[y].p=x;
	pushup(y),pushup(x);
}
void splay(int x,int k,int r)
{
	while(tr[x].p!=k)
	{
		int y=tr[x].p,z=tr[y].p;
		if(z!=k)
		{
			if((tr[z].s[1]==y)^(tr[y].s[1]==x))rotate(x);
			else
				rotate(y);	
		}
		rotate(x);
	}
	if(!k)root[r]=x;
}

void insert(int v,int r)
{
	int u=root[r],p=0;
	while(u)p=u,u=tr[u].s[tr[v].v>tr[u].v];
	u=v;
	if(p)tr[p].s[tr[v].v>tr[p].v]=u;
	tr[u].init(p,tr[v].v);
	splay(u,0,r);
}
void dfs(int v,int u)
{
	if(tr[v].s[0])dfs(tr[v].s[0],u);
	if(tr[v].s[1])dfs(tr[v].s[1],u);
	insert(v,u);
}
int get_k(int u,int k)
{
	while(u)
	{
		if(tr[tr[u].s[0]].sz>=k)u=tr[u].s[0];
		else if(tr[tr[u].s[0]].sz+1==k)return u;
		else
			k-=tr[tr[u].s[0]].sz+1,u=tr[u].s[1];
	}
	return -1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
    	int v;
    	scanf("%d",&v);
    	fa[i]=root[i]=i;
    	tr[i].init(0,v);
    }
    while(m--)
    {
    	scanf("%d%d",&a,&b);
    	a=find(a),b=find(b);
    	if(a!=b)
    	{
    		if(tr[root[a]].sz>tr[root[b]].sz)swap(a,b);
    		dfs(root[a],b);
    		fa[a]=b;
    	}
    }
    scanf("%d",&m);
    while(m--)
    {
    	char op[2];
    	scanf("%s%d%d",op,&a,&b);
    	if(*op=='B')
    	{
    		a=find(a),b=find(b);
	    	if(a!=b)
	    	{
	    		if(tr[root[a]].sz>tr[root[b]].sz)swap(a,b);
	    		dfs(root[a],b);
	    		fa[a]=b;
	    	}
    	}
    	else
    	{
    		a=find(a);
    		printf("%d\n",tr[root[a]].sz>=b?get_k(root[a],b):-1);
    	}
    }
    return 0;
}

标签:sz,int,1063,tr,节点,splay,root,永无
来源: https://www.cnblogs.com/zyyun/p/16462239.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有