hdu 3047 Zjnu Stadium 带权并查集

Zjnu Stadium

题意:题中讲列数总共为300,但是行数不限。即广场每一圈的半径无限大,但是阶梯层数为300;并且每一次输入A(1<=A<=N), B(1<=B<=N), X(0<=X<300)就表示A,B在同一行(列数没用。。不用mod),并且认为B在A的右边X处;N,M分别表示输入的数值不会超过N,叙述不会超过M;还是问里面有几句话与之前的话矛盾;

思路:带权并查集,只需在压缩路径时将dist[]同时增加即可;dist[a] += dist[f[a]];

注后面加的不是dist[fa]虽然前面fa = Find(f[a]);但是是在return 时才f[a] = fa;我们加的是没压缩之前的dist[f[a]],即从后往前递推处理到要累加的u,v的dist;

 

265MS    1960K
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
const int MAXN = 50050;
int f[MAXN],dist[MAXN];
int Find(int a)//**
{
    if(a == f[a]) return f[a];
    int fa = Find(f[a]);
    dist[a] += dist[f[a]];//加上没压缩之前的fa,此时dist[f[a]]已经递推到了要fa的距离
    return f[a] = fa;
}
bool solve(int u,int v,int w)
{
    int fu = Find(u),fv = Find(v);
    if(fu == fv && dist[v] != dist[u] + w) return true;
    f[fv] = fu;
    dist[fv] = dist[u] + w - dist[v];    //  压缩时计算到根节点的距离,现在计算两个根节点距离;
    return false;
}
int main()
{
    int N,M;
    while(scanf("%d%d",&N,&M) == 2){
        rep1(i,0,N)
            dist[i] = 0,f[i] = i;
        int A,B,X,ans = 0;
        rep0(i,0,M){
            scanf("%d%d%d",&A,&B,&X);
            if(solve(A,B,X)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2016-02-07 21:23  hxer  阅读(209)  评论(0编辑  收藏  举报