您的位置:首页 > 其它

带权并查集 - HDU 3038

2017-08-18 13:27 375 查看

题意

给出一些询问区间和询问结果,结果是询问区间内所有数的和,如果新一条询问的结果与原来的结果有冲突,则记录询问结果错误。问询问结果错误的数目。

将区间 [a,b] 内数的和 转化为 b的前缀和 - (a-1)的前缀和。

保持并查集的祖先树的树根在该树中序号最低的位置,这样一个树中节点到树根的每一段距离的和即为 [树根的序号,该节点序号] 的数的和

每次检查新的查询会不会与之前构建的带权并查集冲突,如果不冲突就加入到并查集中

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;

typedef long long LL;

const int inf=0x3f3f3f3f;
const double eps=1e-8;
const int maxn=200005;

int n,m;
int f[maxn],sum[maxn];

int _find(int x){
if(x!=f[x]){
int df=f[x];
f[x]=_find(f[x]);
sum[x]+=sum[df];
}
return f[x];
}

bool _merge(int u,int v,int d){
int fu=_find(u),fv=_find(v);
if(fu==fv){
if(sum[v]-sum[u]!=d){return false;}
}
else if(fu>fv){
f[fu]=fv;
sum[fu]=sum[v]-sum[u]-d;//两种情况下对距离更新的方法不同
}
else {
f[fv]=fu;
sum[fv]=sum[u]-sum[v]+d;
}
return true;
}

void init()
{
for(int i=0;i<=n;++i){
f[i]=i;
}
memset(sum,0,sizeof(sum));
}

int main()
{
while(~scanf("%d%d",&n,&m)){
init();
int a,b,c,ans=0;;
for(int i=0;i<m;++i){
scanf("%d%d%d",&a,&b,&c);
a--;
if(!_merge(a,b,c))ans++;
}
//debug(f,12);
//debug(sum,12);
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: