首页 > 其他分享 >X-Camp 2023 Summer Training 做题泛记

X-Camp 2023 Summer Training 做题泛记

时间:2023-07-19 17:57:45浏览次数:49  
标签:Summer Training int siz cnt textbf 做题 text 操作

由于我懒,本 Blog 只记录暑期集训的难题 & 趣题,当然大部分难题我都不会做。

\(\textbf{D1T2}\)

很奇妙的一题,不过我不会。可以看 xhgua 的博客。

\(\textbf{D5T3}\)

模拟赛放 Ynoi,兄弟。

\(\textbf{D5T3.1 Description}\)

实现一个数据结构,要求实现三个操作:

  • 在图中将两个点连边;
  • 回退到某个历史版本;
  • 查询所有点 \(x\) 可到达的店中所有店中点权第 \(k\) 大。

\(1\le n,m \le 10^5\) 。

\(\textbf{D5T3.2 Solution}\)

很显然的需要使用并查集。口胡了一个启发式合并:每个并查集维护一个 std::vector 当做平衡树维护点权集合。保存所有历史版本即可。但是数据太毒瘤了,全 RE。

后来发现不写撤销操作能拿分,\(14\text{pts}\) 滚粗。

暴力的瓶颈在于空间。

本题最大的空间开销就是撤销操作需要回到历史版本。

注意到不强制在线,考虑把所有的询问离线下来。

std::vector 之类的东西保存所有需要回退的版本编号,只有当当前版本在后续操作中用得到时才保存它。这样可以节省许多不必要的空间开销。

当然这个东西随便卡。而且代码也很难写。


容易将上述思路的「后续操作用得到时保存」转化为「不保存,直接以当前版本为基础完成所有后续操作」。

这和 dfs 是非常类似的:遍历,回溯。于是有一个新的思想:操作树。

操作树就是所有操作组成的树。对于所有操作二,把当前操作编号和所给历史版本时间戳连边,对于操作一和三,把当前操作和上一个操作连边。

读入完询问之后对于操作树遍历一边即可。写一个类似可撤销并查集的东西即可,三个操作直接暴力干。

本题的原题是 Ynoi。因此考虑分块。区间第 \(k\) 大,很显然的值域分块。

点权离散化之后最多 \(10^5\) 个值,对这 \(10^5\) 个值开桶然后对桶分块。

具体地,令 \(\text{cnt}(rt, k)\) 表示根为 \(rt\) 的并查集中,点权属于第 \(k\) 个块所表示的区间的个数。那么点权 \(k\,\text{th}\) 可以轻易地解决:整块扫描过去,直到 \(\sum_{i=1}^{p-1}\text{cnt}(rt,i)\le k\) 且 \(\sum_{i=1}^p\text{cnt}(rt,i)> k\) 。然后扫描原数组(离散化后)上第 \(p\) 个块对应的区间,从小到大枚举属于该并查集的值,什么时候刚好 \(k\) 了直接 break 就行。

细节稍微注意一下,只要不是和我一样把乘写成除就行()

\(\textbf{D5T3.3 AC Code}\)

#include <bits/stdc++.h>

// FastIO

typedef long long i64;
constexpr int N = 1e5 + 5;
constexpr int B = 2000;
int n, m, siz[N], fa[N], tot, ans[N];
unsigned short cnt[N][N / B + 5];

inline int find(int x) {
	return x == fa[x] ? x : find(fa[x]);
}

struct Node { int val, id; } a[N];
struct que { int opt, x, y; } q[N];

struct Edge { int to, nxt; } E[N];
int head[N], idx;

inline void addEdge(int x, int y) {
	E[++idx] = Edge{y, head[x]}, head[x] = idx;
}

inline void mrg(int x, int y) {
	if(siz[x] > siz[y]) x ^= y ^= x ^= y;
	fa[x] = y, siz[y] += siz[x];
	for(int i = 1; i <= tot; i++) {
		cnt[y][i] += cnt[x][i];
	}
}

inline void del(int x, int y) {
	if(siz[x] > siz[y]) x ^= y ^= x ^= y;
	fa[x] = x, siz[y] -= siz[x];
	for(int i = 1; i <= tot; i++) {
		cnt[y][i] -= cnt[x][i];
	}
}

inline int qry(int x, int k) {
	int pos, res = 0;
	x = find(x);
	if(siz[x] < k) return -1;
	for(int i = 1; i <= tot; i++) {
		if(k > cnt[x][i]) k -= cnt[x][i];
		else { pos = i; break; }
	}
	for(int i = (pos - 1) * B + 1; i <= pos * B; i++) {
		if(find(a[i].id) == x && !(--k)) res = a[i].val;
	}
    return res;
}

inline void dfs(int u) {
	bool tag = 0;
	int opt = q[u].opt, x = q[u].x, y = q[u].y;
	if(opt == 1) {
		x = find(x), y = find(y);
		if(x ^ y) {
			mrg(x, y);
			tag = 1;
		}
	} else if(opt == 3) ans[u] = qry(x, y);
	for(int i = head[u]; i; i = E[i].nxt) dfs(E[i].to);
	if(tag) del(x, y);
}

signed main() {
	read(n, m);
	tot = (n - 1) / B + 1;
	for(int i = 1; i <= n; i++) {
		read(a[i].val);
		a[i].id = fa[i] = i;
		siz[i] = 1;
	}
	std::sort(a + 1, a + n + 1, [](Node& lhs, Node& rhs) {
		return lhs.val < rhs.val;
	});
	for(int i = 1; i <= n; i++) {
		cnt[a[i].id][(i - 1) / B + 1]++;
	}
	for(int i = 1; i <= m; i++) {
		read(q[i].opt);
		if(q[i].opt == 2) {
			read(q[i].x);
			addEdge(q[i].x, i);
		} else {
			read(q[i].x, q[i].y);
			addEdge(i - 1, i);
		}
	}
	dfs(0);
	for(int i = 1; i <= m; i++) {
		if(q[i].opt == 3) {
			writeln(ans[i]);
		}
	}
	return flush(), 0;
}

原题链接:[Ynoi2014] 等这场战争结束之后

\(\textbf{D5T4}\)

\(\textbf{D8T1}\)

模拟赛 A 题放黑你见过吗?

标签:Summer,Training,int,siz,cnt,textbf,做题,text,操作
From: https://www.cnblogs.com/Matrixqwq/p/17566340.html

相关文章

  • 大语言模型的预训练[3]之Prompt Learning:Prompt Engineering、Answer engineering、Mu
    大语言模型的预训练[3]之PromptLearning:PromptEngineering、Answerengineering、Multi-promptlearning、Trainingstrategy详解1.PromptLearning1.1PromptLearning的出现背景目前学术界一般将NLP任务的发展分为四个阶段,即NLP四范式::第一范式:传统机器学习模型的范......
  • REALM Retrieval-Augmented Language Model Pre-Training
    目录概REALMGuuK.,LeeK.,TungZ.,PasupatP.andChangM.REALM:Retrieval-augmentedlanguagemodelpre-training.ICML,2020.概赋予生成模型检索的能力.REALM如上图所示,作者希望实现这样一个事情:给定一个'预测'任务,如"The[MASK]atthetopofthep......
  • 复杂最短路做题笔记
    1.CF609EMinimumspanningtreeforeachedgeluogu传送门CodeForces传送门题意给你\(n\)个点,\(m\)条边,对于编号位i的边求出必须包含i的最小生成树权值和。很好理解,不做赘述。题解前置芝士:Kruskal算法求最小生成树,ST表倍增。首先,我们不考虑每条边的限制,先将整张图的......
  • SMU Summer 2023 Contest Round 4
    SMUSummer2023ContestRound4A-TelephoneNumber思路:满足有8,且8后有大于等于11个数#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongtypedefpair<int,int>PII;typedefpair<string,int>PSI;typedefpair<char,int>PCI;type......
  • SMU Summer 2023 Contest Round 4
    SMUSummer2023ContestRound4A.TelephoneNumber满足第一个8后面存在10个字符即可#include<bits/stdc++.h>#defineendl'\n'#defineintlonglongusingnamespacestd;intn,m;voidsolve(){cin>>n;strings;cin>>s;......
  • 做题记录
    一些自己错的题目或者难题的相关记录,有些错的很不应该.7月质数是1*pr,而非1*pr*pr*pr...线段树要可以维护当前区间没有abc的最少操作(s[x]->c)structnode{intl,r;inta,b,c;//thenumsofthemintab,bc,abc;//删除需要的操作}t......
  • SMU Summer 2023 Contest Round 3
    SMUSummer2023ContestRound3A-CurriculumVitae思路:要求0后不能有1,当某个数都不删时,值为前面所有的0的个数加后面所有1的个数,求出最大即可#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongtypedefpair<int,int>PII;typedefpair<string,int>......
  • SMU Summer 2023 Contest Round 2
    SMUSummer2023ContestRound2A-TreasureHunt思路:判断Δx和Δy能否分别整除x和y,求出需要的步数,两者的步数须同奇或同偶#include<bits/stdc++.h>usingnamespacestd;//#defineintlonglongtypedefpair<int,int>PII;typedefpair<string,int>PSI;type......
  • SMU Summer 2023 Contest Round 1
    SMUSummer2023ContestRound1A-TheContest思路:求出最短解决问题总时间,在所有区间找出大于等于总时间的最短时刻。#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongtypedefpair<int,int>PII;typedefpair<string,int>PSI;typedefpair<strin......
  • 做题思考总结
    $做题总结$每次做之前看一看。做题千万不要分心,不要做一下这道题就去干别的事。OI思想:正反,抽象,等效,益少,独立对于OI思想的一些思考与理解独立:对于那些会改变的值,比如说数组之类的,显然他的下标的关联越少越好。比如f[k]和f[i-j]相比,肯定是前者更好,因为前者更为固定,通常可以通......