P1196 [NOI2002]银河英雄传说[带权并查集]

P1196 [NOI2002]银河英雄传说


对于任意两艘舰,查询是否在同一列就是看在不在同一集合,并查集。询问距离的话,把每个点和他父亲的连边带上权值表示距离(父亲不一定就是前一艘舰),查询时会顺便压缩路径,一路回来会把所有点直接连边向根节点,这时边权改为他父亲(已直指根节点)的dis加上自己到父亲的dis,再连边向根。所以每次询问会把两个点到根的距离处理好,就可以出结果了。对于路径已压缩的点再查也不会出错。

然后是合并问题。将x的根要并到y集合中,而x的根迟早是要被压缩路径的,不妨现在就把他连一个边到y的根节点权值是y集合战舰数量(也就是把x根接在y最后,其到队首的距离)。

上述均摊复杂度$O(NlogN)$,然后可以加一些合并的优化什么的,复杂度基本就是$O(Nα(N))$了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl
 8 #define ddbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
 9 using namespace std;
10 typedef long long ll;
11 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
12 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
15 template<typename T>inline T _abs(T A){return A<0?-A:A;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 const int N=30000+7;
21 int fa[N],dis[N],siz[N],T,x,y;
22 char s[3];
23 inline int Get(int x){
24     if(fa[x]==x)return x;
25     int ret=Get(fa[x]);
26     dis[x]+=dis[fa[x]];
27     return fa[x]=ret;
28 }
29 inline void Merge(int x,int y){
30     int fx=Get(x),fy=Get(y);
31     if(siz[fx]>siz[fy])x^=y^=x^=y;//按秩合并的优化 
32     fa[fx]=fy,dis[fx]=siz[fy],siz[fy]+=siz[fx];
33 }
34 
35 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
36     read(T);
37     for(register int i=1;i<=3e4;++i)fa[i]=i,siz[i]=1;//dis[i]=0;
38     while(T--){
39         scanf("%s",s);read(x),read(y);
40         if(s[0]=='M')Merge(x,y);
41         else Get(x)^Get(y)?printf("-1\n"):printf("%d\n",_abs(dis[x]-dis[y])-1);
42     }
43     return 0;
44 }

 

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/10625199.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值