并查集——UVA - 1329

在这里插入图片描述

有 n 个结点(5 <= n <= 20000),初始时每个结点都没有父结点。你的任务是执行 I 操作和 E 操作,格式如下:
·I u v:把结点 u 的父结点设为 v,距离为 | u - v | mod 1000。
输入保证执行指令前 u 没有父结点。
·E u:询问 u到根结点的距离。

自己一开始的思路:不用记录距离,
I:改变父亲节点
E:用循环直到找到根节点

do{
ans += abs(u - pre[u]) % 1000;
u = pre[u];
}while(u!=pre[u]);
cout << ans << endl;

自己感觉思路挺对的。
但是超时:不要超过10 ^ 7
但是假设每次都查询最长的那个,就会超。
所以用d记录

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<vector>
#include<cstring>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn = 20005;

int pre[maxn];
int n;
int d[maxn];
int mod = 1000;

//不用join函数,给出的直接是父亲节点
//find:寻找最短的权值相加
int find(int x){
    if(pre[x]==-1)
        return x;
    int t = find(pre[x]);   //往上找
    d[x] += d[pre[x]];
    return pre[x] = t;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(pre,-1,sizeof(pre));
        memset(d,0,sizeof(d));
        char op;
        int u,v;
        while(~scanf("%c",&op)){
            if(op=='0')
                break;
            else if(op=='E'){
                scanf("%d",&u);
                find(u);
                printf("%d\n",d[u]);
            }
            else if(op=='I'){
                scanf("%d %d",&u,&v);
                pre[u] = v;
                d[u] = abs(u-v) % mod;
            }
        }
    }
    return 0;
}

发布了62 篇原创文章 · 获赞 0 · 访问量 1736

猜你喜欢

转载自blog.csdn.net/jhckii/article/details/104578925