Corporative Network UVA - 1329(并查集的修改与查询)

题目链接:https://vjudge.net/problem/UVA-1329

题目描述:给定n个点,一开始其父节点都是其自身。两个直接相连的结点uv间的距离是abs(u - v) % 1000。进行两种操作,E i 代表查询i到其父节点的距离,I i j表示将i的前驱结点设为j(i j直接相连)。其实也就是修改了一些父节点的值,求某个结点到根节点的距离。在贴场上写的AC代码前突然想到一组样例自己的代码不知道能不能过,一试果然不能通过,可是还是AC了,可能测试数据太水了吧。场上写的是很普遍的并查集写法,只是在Find(x)回溯时求出当前节点到其根节点的距离。虽然能AC可是过不了自己出的一组样例。换了一种写法,不再记录每个点到其根节点的距离,而是在E i 时直接通过不停沿着父节点找到根节点,在找的过程中计算距离,这种方法可以过所有的样例,场上怕超时没那样写。下面附上两种代码,代码最后附上卡住自己的样例。不知道真的是数据太水还是我自己理解有误,欢迎大家指正或赐教。

代码如下:

场上AC但是过不了自己出的样例的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int  maxn = 20000 + 10;
const int  maxt = 300 + 10;
const int mod = 10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const int inf = 0x3f3f3f3f;
const int MOD = 1000;
int n, m, k;
int dis[maxn][maxn], fa[maxn];
int Find(int x){
    if(x == fa[x]) return x;
    int y = Find(fa[x]);
    dis[x][y] = dis[x][fa[x]] + dis[fa[x]][y];//回溯前记录当前节点到其根节点的距离=当前节点到其父节点距离+其父节点到根节点的距离
    return  fa[x] = y;//修改根节点
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        memset(dis, 0, sizeof dis);
        getchar();
        for(int i = 0; i < maxn; ++i) fa[i] = i;
        char ch[5];
        int x, y, xx, yy;
        while(scanf("%s", &ch) == 1){
            if(ch[0] == 'O') break;
            if(ch[0] == 'E'){
                scanf("%d", &x);
                y = Find(x);
                printf("%d\n", dis[x][y]); continue;//输出x到其根节点y的距离
            }
            if(ch[0] == 'I'){
                scanf("%d%d", &x, &y);//y是x的父节点
                if(x == y){
                    dis[x][y] = 0; fa[x] = x;
                    continue;
                }
                yy = Find(y);//找到新的根节点
                fa[x] = yy;
                dis[x][yy] = dis[y][yy] + (abs(x - y) % MOD);}
        }
    }
    return 0;
}
/*
此代码无法通过该组样例:
1
6
E 3
I 3 1
E 3
I 1 2
E 3
I 2 4
E 1
E 3
I 2 5
I 5 6
E 2
E 1
E 3
O


*/

记录父节点,在查询时现求当前节点到根节点的距离的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int  maxn = 20000 + 10;
const int  maxt = 300 + 10;
const int mod = 10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const int inf = 0x3f3f3f3f;
const int MOD = 1000;
int n, m, k;
int dis[maxn][maxn], fa[maxn];
int Find(int x){//返回x到其当前根节点的距离
    if(x == fa[x]) return 0;
    int num = 0;
    while(x != fa[x]){//从前驱节点一直向前求距离直至求到根节点
        num += abs(fa[x] - x) % MOD;
        x = fa[x];
    }
    return num;
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        memset(dis, 0, sizeof dis);
        for(int i = 0; i < maxn; ++i) fa[i] = i;
        char ch[5];
        int x, y;
        while(scanf("%s", ch) == 1){
            if(ch[0] == 'O') break;
            if(ch[0] == 'E'){
                scanf("%d", &x);
                printf("%d\n", Find(x)); continue;
            }
            if(ch[0] == 'I'){
                scanf("%d%d", &x, &y);
                fa[x] = y;//将x的前驱节点(父节点)设为y
            }
        }
    }
    return 0;
}

/*
此代码可以通过该组样例:
1
6
E 3
I 3 1
E 3
I 1 2
E 3
I 2 4
E 1
E 3
I 2 5
I 5 6
E 2
E 1
E 3
O

*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值