首页 > 其他分享 >Luogu P3224 [HNOI2012]永无乡

Luogu P3224 [HNOI2012]永无乡

时间:2023-06-07 21:14:45浏览次数:44  
标签:ch HNOI2012 int Luogu tree leq P3224 include id

[HNOI2012]永无乡

题目描述

永无乡包含 \(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\) 个整数,第 \(i\) 个整数表示编号为 \(i\) 的岛屿的排名 \(p_i\)。

接下来 \(m\) 行,每行两个整数 \(u, v\),表示一开始存在一座连接编号为 \(u\) 的岛屿和编号为 \(v\) 的岛屿的桥。

接下来一行有一个整数,表示操作个数 \(q\)。

接下来 \(q\) 行,每行描述一个操作。每行首先有一个字符 \(op\),表示操作类型,然后有两个整数 \(x, y\)。

  • 若 \(op\) 为 Q,则表示询问所有与岛 \(x\) 连通的岛中重要度排名第 \(y\) 小的岛是哪座,请你输出那个岛的编号。
  • 若 \(op\) 为 B,则表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。

输出格式

对于每个询问操作都要依次输出一行一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 \(-1\) 。

样例 #1

样例输入 #1

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

-1
2
5
1
2

提示

数据规模与约定

  • 对于 \(20\%\) 的数据,保证 \(n \leq 10^3\), \(q \leq 10^3\)。
  • 对于 \(100\%\) 的数据,保证 \(1 \leq m \leq n \leq 10^5\), \(1 \leq q \leq 3 \times 10^5\),\(p_i\) 为一个 \(1 \sim n\) 的排列,\(op \in \{\texttt Q, \texttt B\}\),\(1 \leq u, v, x, y \leq n\)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define lid (tree[id].lson)
#define rid (tree[id].rson)

using namespace std;

int n, m, q, tot, val[5211314];
int fa[5211314];
int root[5211314];

struct Segment_Tree {
	int lson, rson;
	int sum;
	int Rank;
}tree[5211314];

inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch - '0');
		ch = getchar();
	}
	return x * f;
}

struct DisjointSetUnion {
	int Find(int x) {
		if (fa[x] == x) return x;
		else return fa[x] = Find(fa[x]);
	}
	bool Check(int x, int y) {
		if (Find(x) == Find(y)) return true;
		else return false;
	} 
}dsu;

struct MergeSegmentTree {
	inline void PushUp(int id) {
		tree[id].sum = tree[lid].sum + tree[rid].sum;
		return;
	}
	void Update(int &id, int l, int r, int pos, int ans) {
		if (id == 0) id = ++ tot;
		if (l == r) {
			tree[id].sum = 1;
			tree[id].Rank = ans;
			return;
		}
		int mid = (l + r) >> 1;
		if (pos <= mid) Update(lid, l, mid, pos, ans);
		else Update(rid, mid + 1, r, pos, ans);
		PushUp(id);
		return;
	}
	int Merge(int a, int b, int l, int r) {
		if (a == 0) return b;
		if (b == 0) return a;
		if (l == r) {
			tree[a].sum += tree[b].sum;
			tree[a].Rank = tree[b].Rank;
			return a;
		}
		int mid = (l + r) >> 1;
		tree[a].lson = Merge(tree[a].lson, tree[b].lson, l, mid);
		tree[a].rson = Merge(tree[a].rson, tree[b].rson, mid + 1, r);
		PushUp(a);
		return a;
	}
	int Query(int id, int l, int r, int k) {
		int mid = (l + r) >> 1, ans;
		if (tree[id].sum < k || id == 0) return 0;
		if (l == r) return tree[id].Rank;
		if (k <= tree[lid].sum) ans = Query(lid, l, mid, k);
		else ans = Query(rid, mid + 1, r, k - tree[lid].sum);
		return ans;
	}
}ask;

inline void Union(int u, int v) {
	u = dsu.Find(u);
	v = dsu.Find(v);
	if (u == v) return;
	root[u] = ask.Merge(root[u], root[v], 1, n);
	fa[v] = u;
	return;
}

int main() {
	n = read();
	m = read();
	for (int i = 1; i <= n; ++ i) {
		val[i] = read();
		fa[i] = i;
		ask.Update(root[i], 1, n, val[i], i);
	}
	for (int i = 1, u, v; i <= m; ++ i) {
		u = read(), v = read();
		Union(u, v);
	}
	q = read();
	for (int i = 1, x, y; i <= q; ++ i) {
		char ch = getchar();
		while (ch != 'Q' && ch != 'B') {
			ch = getchar();
		}
		x = read();
		y = read();
		if (ch == 'B') {
			Union(x, y);
		}
		else {
			x = dsu.Find(x);
			//注意这里一定要用find(x)的而不是fa[x]的值
			//因为这里的x可能刚更新过,fa[x]的值不是合并后线段树的根节点的值
			if (tree[root[x]].sum < y) printf("-1\n");
			else {
				printf("%d\n", ask.Query(root[x], 1, n, y));
			}
		}
	}
	return 0;
}

标签:ch,HNOI2012,int,Luogu,tree,leq,P3224,include,id
From: https://www.cnblogs.com/jueqingfeng/p/17464559.html

相关文章

  • [刷题笔记] Luogu P3073 [USACO13FEB]Tractor S
    ProblemSolution和汽车拉力比赛差不多,思路都是二分,二分\(d\),但是汽车拉力比赛从一个路标开始搜即可,本题没有给定起点。一条合法路径起点是未知的,不得随便从一个点开始搜,否则可能找不到正确路径。怎么处理呢?容易想到对于每一个二分的\(d\),开一个\(n^2\)的循环,从每一个点开始搜......
  • Luogu P3605 [USACO17JAN]Promotion Counting P
    [USACO17JAN]PromotionCountingP题目描述Thecowshaveonceagaintriedtoformastartupcompany,failingtorememberfrompastexperiencethatcowsmaketerriblemanagers!Thecows,convenientlynumbered\(1\ldotsN\)(\(1\leqN\leq100,000\)),o......
  • Luogu P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
    [Vani有约会]雨天的尾巴/【模板】线段树合并题目背景深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。无奈......
  • LuoguP4318 完全平方数
    标签:莫比乌斯函数,容斥完全平方数题目描述小X自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。这天是小X的生日,小W想送一个数给他作为生日礼物。当然他......
  • Luogu P2709 小B的询问
    https://www.luogu.com.cn/problem/P2709#submit小B的询问题目描述小B有一个长为\(n\)的整数序列\(a\),值域为\([1,k]\)。他一共有\(m\)个询问,每个询问给定一个区间\([l,r]\),求:\[\sum\limits_{i=1}^kc_i^2\]其中\(c_i\)表示数字\(i\)在\([l,r]\)中的出现次数......
  • [刷题笔记] Luogu P2895 Meteor Shower S
    ProblemSolution显然bfs,只不过有了限定条件,有实时的流星雨这里提供两种做法:Solution1这也是我一开始的做法模拟实时流星,由于bfs是按层搜的,是严格按照时间递增搜的,故可以模拟实时放流星。需要注意放流星的时间,如果第\(t\)秒有流星,则该秒不可以走,需要在每一秒前放流星。那......
  • [刷题笔记] LuoguP2658 汽车拉力比赛
    ProblemSolution需要找到最小满足题意的\(d\),显然\(d\)满足单调性,考虑二分二分\(d\),然后直接bfs,每次bfs判断能不能走的时候还需要加上高度差不超过二分的\(d\)(即满足),bfs跑完后看看所有的路标都被访问了没。(可以记录个数,因为不可能重复走)二分的时候注意\(l\)从0开始,不然会WA......
  • luogu P8497 [NOI2022] 移除石子
    题面传送门不好评价?首先我们考虑最基础的情况,当\(k=0,l_i=r_i\)时,相当于我们需要判定一个状态能不能被消完。这相当于我们要执行若干次\(2\)操作,使得每个位置要么大于等于\(2\),要么为\(0\)。为此我们需要挖掘一些操作\(2\)的性质。性质\(1\):操作区间长度不会超过\(5......
  • Luogu P1007 独木桥
    题目描述link思路找到独木桥的中间位置,最少时间考虑在端点左侧的,向左走,在端点右侧的向右走.最多时间考虑在端点左侧的向右走,在端点右侧的向左走.最少时间即为最优情况下最多的时间,最多时间即为最差情况下的最多时间Code#include<cstdio>#include<algorithm>......
  • Luogu P1008 三连击
    题目描述link思路因为\(1-9\)且不能重复使用,所以从\(123\)循环至\(789\),相应的\(2\)倍,\(3\)倍,即为另两个数字.对每个数字进行拆分,所用数字使用次数\(+1\),判断是否每个数字都被使用且只使用一次,输出即可.Code#include<cstdio>#include<cstring>i......