hdu3047 Zjnu Stadium(带权并查集)

题目

1-300列,无限行

N个人,每人坐在一列

M个叙述,表示A所在的列在B所在的列的前x列

问有多少种说法是假的

即若A在B的前x1列,A又在B的前x2列,则假

思路来源

https://blog.csdn.net/shuangde800/article/details/7983965

https://blog.csdn.net/xiaolonggezte/article/details/53025150

题解

学了并查集这么久竟然没入带权并查集

可以说是很菜了

有个等价的食物链的题 可以用三个集合的合并关系来搞

但思路不如这个简单

 

每棵树上维护这个节点到根节点的距离,即相距列数

A所在的树与B所在的树合并的时候,

不妨记A所在树树根root1,B所在树树根root2

令par[root2]=root1,即把root2挂在root1上

只改root2这个根节点

 

在root1这棵新树里,即以root1为0列

A排在pos[A]列,B比A后x列即(pos[A]+x)列

而root2比B前pos[B]列,则root2排在(pos[A]+x-pos[B])列

 

只改根,查询叶子结点的时候

把这条链的父亲节点的父亲,

都压缩为根,

利用回溯时,从根到叶,

搞链的前缀和,

相当于令该节点一步连根

 

2020年3月19日补充:

图片来源于Lazines_by的博客,此时要确定的是fa[a]和fa[b]的相对大小,

即fa[b]=0时,b比fa[b]大d[y],而a比b小z,fa[a]比a大d[x],

显然fa[a]相对于fa[b]的位次为-d[x]+z+d[y],

未路径压缩时,是相对于自己的根的相对rank,路径压缩时是相对于新根的相对rank

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=5e4+10;
int n,m;
int a,b,x,ans;
int par[maxn],pos[maxn];
void init()
{
	for(int i=1;i<maxn;++i)
	{
		par[i]=i;
		pos[i]=0;
	}
	ans=0;
}
int find(int x)
{
	if(par[x]==x)return x;
	int fa=par[x];//直接基类 
	par[x]=find(par[x]);//路径压缩 
	pos[x]+=pos[fa];//树上前缀和 两链变一链 直接连树根 
	return par[x];//返回树根 
}
bool unite(int x,int y,int v)//y比x大v 
{
	int px=find(x),py=find(y);
	if(px==py)
	{
		if(pos[x]+v!=pos[y])return 0;
		return 1; 
	}
	//把y所在树的树根挂在x所在树的树根上 只改树根py 
	par[py]=px;//rank[py]=rank[y现在]-rank[y之前]==(rank[x]+v)-rank[y] 
	pos[py]=pos[x]+v-pos[y];//注意rank可能有负 与将负旋为0的根是等价的
	return 1; 
} 
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		init();
		while(m--)
		{
			scanf("%d%d%d",&a,&b,&x);
			if(!unite(a,b,x))ans++;
		}
		printf("%d\n",ans); 
	}
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值