题意:一个企业要去收购一些公司把,使的每个企业之间互联,刚开始每个公司互相独立
给出n个公司,两种操作
E I:询问I到I它连接点最后一个公司的距离
I I J:将I公司指向J公司,也就是J公司是I公司的上级,距离为abs(I-J)%1000(貌似G++不支持abs,PE了两发)
思路:转化一下题意就行了,首先刚开始的时候每个公司都是独立的,I操作就是并查集中合并操作,将I这课树并到J这个树上,
E操作要求的东西就是 I到I的根节点的距离,先看一个没有路径压缩直接暴力的方法把、(本以为不会过的,因为数据很大)
时间是:2222ms 被系统藐视了
等等,现已题目中所给的例子来把 直接执行完I 操作 ,最后得到的是 3->1->2->4
那么E 3所得到的结果是 (3-1)%1000+(2-1)%1000+(4-2)%1000=5
并查集本身就是这样的结果,所以直接从子节点向根节点找过去,一边找一遍求距离
#include<cstdio> #include<cstring> #include<cmath> const int qq=20000+5; int pre[qq],sum[qq]; int ans; void init(int n) { for(int i = 0; i <= n; ++i){ pre[i]=i; sum[i]=0; } } int find(int x) { if(x==pre[x]) return x; else{ int dis=x-pre[x]>0?x-pre[x]:pre[x]-x; dis%=1000; ans+=dis; return find(pre[x]); } } int main() { int t,n;scanf("%d",&t); while(t--){ scanf("%d",&n); init(n); char s[10]; while(scanf("%s",s) && (s[0]!='O')){ if(s[0] == 'E'){ int a; scanf("%d",&a); ans = 0; find(a); printf("%d ",ans); } else if(s[0] == 'I'){ int a,b; scanf("%d%d",&a,&b); pre[a] = b; } } } return 0; }
路径压缩版、 66MS
#include<cstdio> #include<cstring> #include<cmath> const int qq=20000+5; int pre[qq],dis[qq]; int ans; void init(int n) { for(int i = 0; i <= n; ++i){ //初始化、 pre[i]=i; dis[i]=0; } } int find(int x) //只想说递归的调用真的很神奇,然而我还是个半桶水 { if(x==pre[x]) return x; int flag=find(pre[x]); // 在find函数中直接进行路径压缩 dis[x]=dis[x]+dis[pre[x]]; // 一边压缩一遍更新子节点到根节点的距离值 return pre[x]=flag; //这里是压缩路径、 } int main() { int t,n;scanf("%d",&t); while(t--){ scanf("%d",&n); init(n); char s[10]; while(scanf("%s",s) && (s[0]!='O')){ if(s[0] == 'E'){ int a; scanf("%d",&a); find(a); //对于要找的那个a,在此之前去压缩路径并更新到根节点的距离值 printf("%d ",dis[a]); } else if(s[0] == 'I'){ int a,b; scanf("%d%d",&a,&b); pre[a]=b; // 合并 int ans=a-b>0?a-b:b-a; ans%=1000; //求距离、 dis[a]=ans; //然后赋值 } } } return 0; }