首页 > 其他分享 >ABC328F题解

ABC328F题解

时间:2023-11-12 20:58:04浏览次数:38  
标签:ch 题解 ABC328F 合并 fa 操作 节点 dis

原题链接 洛谷题面 提交记录

闲话

赛场就做了这道和 A,喜提 \(625\) 大分。

带权并查集练手题,有点像银河英雄传说

题目大意

存在一个长度为 \(N\) 的数列 \(X\),给定 \(Q\) 个三元组 \((a_i,b_i,d_i)\),定义一个好集合为集合 \(S\subseteq\{1,2,\dots,Q\}\),使得所有 \(x\in S\) 满足 \(X_{a_i}-X_{b_i}=d_i\)。
初始 \(S\) 为空集,以从 \(1\) 到 \(Q\) 执行以下操作:

设当前操作的数为 \(i\),如果 \(S\cup\{i\}\) 为好集合,则以 \(S\cup\{i\}\) 代替 \(S\)。

以升序打印出 \(S\) 中的元素。

题目分析

既然题目让我们从 \(1\) 到 \(Q\) 执行操作,那我们也从 \(1\) 到 \(Q\) 考虑。

对于这个操作我们只需判断是否与以前的操作构成数列的相对关系矛盾即可。

如果没有规定 \(X_{a_i}\) 与 \(X_{b_i}\) 有什么关系的话,直接添加 \(i\) 即可。
如果规定过 \(X_{a_i}\) 与 \(X_{b_i}\) 的关系,则判断这两个 \(X_{a_i}-X_{b_i}\) 是否相同,相同则添加。

这个关系是逐步添加却不会消失的,也会有传递性。
于是我就想到了并查集。

我们还要维护这两个值的差,于是我们可以使用带权并查集。

对于有关系的数就是合并在一个集合里,我们维护父节点与每个节点的差(也可维护相反数,本质相同)即可。

没有关系就不在一个集合里,进行合并操作。
有关系我们就判断差是否相等,相等就输出即可,因为这个关系的添加与否是等效的(不添加原来的操作也能判断关系),所以我们不进行合并操作也可以。

使用路径压缩的查询

设 \(dis_i\) 为 \(i\) 节点的父节点与其的差。
如下图,\(fa_3=2\),\(fa_2=1\),路径压缩压缩前我们可知
\(X_3+dis_{3old}=X_2\),\(X_2+dis_{2old}=X_1\),压缩后的 \(dis_{3new}=X_1-X_3\) 移项代入化简可得 \(dis_{3new}=dis_{2old}+dis_{3old}\)。

查询时该节点 \(i\) 的父节点 \(fa_i\) 如果是它自己就直接返回自己,否则先查询 \(fa_{i}\)(得到 \(dis_{fa_i}\) 为 \(fa_i\) 与祖先的距离,否则 \(dis_{fa_i}\) 为 \(fa_i\) 与父节点的距离,可能出错)。查询完用上式累加到 \(dis_i\) 上即可。

合并

我们只需考虑不同集合的合并(因为相同的没必要合并)。
这里合并使 \(fa_{fa_x}\) 指向 \(fa_y\)。
我们需要满足 \(X_{x}-X_{y}=w\),但并查集的操作时在祖先节点上的操作,需要进行一定的转化。
由上式和 \(X_{x}+dis_{y}=X_{fa_{x}}\) 与 \(X_{y}+dis_{y}=X_{fa_{y}}\),移项代入得 \((X_{fa_{x}}-dis_{x})-(X_{fa_{y}}-dis_{y})=d_i\),又因合并后 \(dis_{fa_x}+X_{fa_x}=X_{fa_y}\),则 \(dis_{fa_x}=w+dis_y-dis_x\)。
对其赋值即可。

代码中的 check 是来检测是否可以添加 \(i\) 的,在上面已经讲过。

代码如下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAXN=2e5+10;
int a,b,d,fa[MAXN],N,Q;
ll dis[MAXN];
int read(){
	int f=1,x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return f*x;
}
int sget(int x){
	if(fa[x]==x)return x;
	int root=sget(fa[x]);
	dis[x]+=dis[fa[x]];
	return fa[x]=root;
}
void merge(int x,int y,int w){
	int fx=sget(x),fy=sget(y);
	if(fx!=fy){
		fa[fx]=fy;
		dis[fx]=w+dis[y]-dis[x];
		//X_x-X_y=w
		//dis[x]+dis[fx]-(dis[y]+dis[fy])=w
	}
}
bool check(){
	int faa=sget(a),fab=sget(b);
	if(faa!=fab||dis[b]+d==dis[a])return true;
	else return false;
}
int main(){
	N=read();Q=read();
	for(int i=1;i<=N;++i){
		fa[i]=i;
	}
	for(int i=1;i<=Q;++i){
		a=read();b=read();d=read();
		if(check()){
			merge(a,b,d);
			printf("%d ",i);
		}
	}
	return 0;
}

标签:ch,题解,ABC328F,合并,fa,操作,节点,dis
From: https://www.cnblogs.com/LiJoQiao/p/17827780.html

相关文章

  • 题解:[春季测试 2023] 幂次
    题解:[春季测试2023]幂次给定\(n,k\),求有多少个整数\(i\in[1,n]\),满足\(i=a^b(a,b\inN^+,b\geqk)\)算法一\(k\ge3:\)发现只需要筛到1e6就没有贡献了,加上\(set\)暴力判重即可。\(k=2:\)发现有\(\sqrt{n}\)个完全平方数,考虑如何避免算重它们。考虑完全平......
  • Tenzing and Random Operations CF1842G 题解
    设\(m\)次选的位置分别为\(b_{1\simm}\)。于是答案为\(\mathbbE(\prod\limits_{i=1}^{n}(a_i+\sum\limits_{j=1}^{m}[b_j\lei]\cdotv))=\frac{S}{n^m}\)。首先考虑期望很难做,希望将期望转化为概率形式,发现这样有点困难。再考虑因为所有方案等概率,将求期望转化......
  • P2687 [USACO4.3] 逢低吸纳 题解
    双倍经验分析这是一道求最长下降子序列的题目,且要统计方案,但是会有重复情况,例如以下的的数据,44223我们可以选择\(1,2\),\(1,2\),\(1,4\)这几天来购买,但是\(1,2\)和\(1,3\)本质上是一样的,所以只算一种。根据上面的说明,我们可以得出:当\(dp_j+1=dp_i\)......
  • [题解] P9838 挑战 NPC IV
    P9838挑战NPCIV定义\(f(x)=1+\log_2\operatorname{lowbit}(x)\)。定义一个\(1\simn\)的排列\(p\)的权值是\(\sum_{l=1}^n\sum_{r=l}^n\sum_{i\in[l,r]}f(p_i)。\)求所有\(1\simn\)的排列中权值第\(k\)小的排列的权值,对\(998244353\)取模。......
  • 【2023 #84】 锦城ACM周测 (大二个人赛) 题解
    题目难度\(B<D<E=C<A\)A:提高+/省选-B:普及-C:普及/提高-D:普及/提高-E:普及/提高-CandywarQuestion有\(N\)个盒子摆成环形,第\(i\)和盒子里面有\(a_i\)个糖果,他们开始在\(1\)好盒子,然后每个人取一次,可以取\(1\),或者小于当前盒子内糖果数的一个质数\(p\),......
  • chatgpt的api联网报错问题解决:openai公司的api联网报错解决
    chatgpt是啥,这里不讲,openai是啥这里也不讲。要知道我们不论是通过网页web使用chatgpt还是使用api方式通过客户端使用chatgpt都是需要使用外国IP的,     ......
  • 「题解」P6791 [SNOI2020] 取石子
    anti-game没有用,能取到\(n-1\)的必胜,不能取到\(n-1\)的必败,所以现在考虑取走最后石子获胜的情况。对于一个\(n\)来说合法的\(k\)一定是一个前缀,并且一定是贪心取最小的(留给对方的机会更小),所以启发将每个\(n\)最小的合法的\(k=a_n\)打出表来,找到最小的\(j\)满足\(......
  • 【洛谷 P2669】[NOIP2015 普及组] 金币 题解(循环)
    [NOIP2015普及组]金币题目背景NOIP2015普及组T1题目描述国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币……;这种工资发放模式会一直这......
  • ABC 328 题解
    A直接模拟即可。cin>>n>>m;for(inti=1;i<=n;++i){ intx;cin>>x; if(x<=m)sum+=x;}cout<<sum;B直接模拟即可。intn,ans;boolchk(intx,inty){ intdig=x%10;x/=10; while(x){ if(x%10!=dig)return0; x/=10; } while(y){ if(y%10......
  • ABC328F 题解
    blog。提供一个普通并查集+启发式合并做法。考虑直接维护\(X_i\)。对于\(X_u-X_v=w\),分四种情况。\(X_u,X_v\)都没被维护过。直接钦定\(X_u\getsw,X_v\gets0\),以后再改。\(X_u\)没被维护过,\(X_v\)被维护过。显然\(X_u\getsX_v+w\)。\(X_v\)没被维护过,\(X_u\)被......