有 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;
}