1.模板题
我们把这个问题换一种方式表述
1 u v 表示v是u的祖先
2 u v 问你u和v是不是同一家族
此处设一些变量
anc[i]表示i的祖先,一开始anc[i]=0。
然后对于输入的信息1 u v
我们找到u和v所已知最早的祖先fu,fv;
while(!anc[u]) u=anc[u];
类似于此
此时如果fu==fv说明之前已经有信息把u,v连接在了一起,则不做处理;
如果fu!=fv,那么另anc[fu]=fv;
(注意此题我们可能无法确定fu与fv谁是最早祖先,但是不影响正确性)
对于输入的询问2 u v
我们也是找到 fu fv
看fu fv 是否相等就可以了
然而我们仔细思考这个过程发现在极端情况下,耗时会十分的长
例如给定信息表示1与2,2与3,3与4,4与5........n与n-1的关系
那么这些元素将会连成一条链
我们每次查询1 的最早祖先, 都要找n次
这样就会使时间复杂度过高
思考我们怎么优化这个过程呢?
路径压缩:
首先对于一个家族里面所有的人,我不关心别的,只关心这个家族最早的祖先
那么我们是不是可以考虑把每个点都直接连接在哪个最早祖先上。
下面给出代码:
1 #include<cstdio> 2 const int N=10005; 3 int anc[N]; 4 int fi(int a){ 5 int b=a; 6 while(anc[b]) b=anc[b]; 7 while(anc[a]){ 8 int t=anc[a]; 9 anc[a]=b; 10 a=t; 11 } 12 return b; 13 } 14 int main(){ 15 int n,m; 16 scanf("%d%d",&n,&m); 17 while(m--){ 18 int id,u,v; 19 scanf("%d%d%d",&id,&u,&v); 20 int fu=fi(u),fv=fi(v); 21 if(id==2){ 22 if(fu==fv) printf("Y "); 23 else printf("N "); 24 } 25 else if(fu!=fv) anc[fu]=fv; 26 } 27 return 0; 28 }
一些加权并查集的题解: