2 条题解

  • 1
    @ 2025-9-10 16:02:49

    這道題考察帶權並查集,帶權並查集與普通並查集的區別就是在每一條邊上都帶一個權值,然後我們在find的時候把這個點到其集合中的最初祖先的權值記錄下來,因為這個東西不會再改變了

    那麼這道題,首先我們定義 fxf_x 表示我們 xx 節點的父親, disxdis_x 表示 xx 節點下麵有多少塊磚, lenxlen_x 表示我們 xx 這個點的集合中一共有多少塊磚

    合併與詢問很簡單,讀者自己證明

    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    bool Test_MLE_start;
    constexpr int N=3*1e5+10;
    int _=1,f[N],len[N],dis[N];
    inline int reads(){
    	char c=getchar();
    	int sum=0,f=1;
    	while(!isdigit(c)){
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(isdigit(c)){
    		sum=(sum<<3)+(sum<<1)+(c^'0');
    		c=getchar();
    	}
    	return sum*f;
    }
    inline void files(){
    	freopen("A.in","r",stdin);
    	freopen("std.out","w",stdout);
    }
    inline void clr(){
    //	Don't forget!
    
    }
    int finds(int x){
    	if(f[x]==x) return x;
    	int fa=finds(f[x]);
    	dis[x]+=dis[f[x]];return f[x]=fa;
    }
    void merges(int x,int y){
    	x=finds(x),y=finds(y);
    	f[x]=y;dis[x]+=len[y];len[y]+=len[x];
    }
    void asks(int x){finds(x);printf("%lld\n",dis[x]);}
    bool Test_MLE_end;
    signed main(){
    //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
    //	files();
    	for(int i=1;i<=100000;i++) f[i]=i,len[i]=1;
    	_=reads();
    	while(_--){
    		clr();int opt,x,y;opt=reads();
    		if(opt&1) x=reads(),y=reads(),merges(x,y);
    		else x=reads(),asks(x);
    	}
    	return 0;
    }
    
    • -1
      @ 2025-9-9 8:56:24

      带权并查集

      每一摞砖作为一个集合

      对于每个点 x(砖的编号),维护:

      1、每块砖 x 所在集合的祖先 fa[x]

      2、每块砖 x 所在的集合有多少块砖 siz[fa[x]]

      3、x 到最上方砖块即祖先的距离dist[x]

      带权并查集其实就是在查找、合并的时候顺便维护一些权值。

      维护的信息根据题目可以自己设定。

      思考:你还能想到维护哪些信息可以解决本题?

      #include<bits/stdc++.h>
      using namespace std; 
      const int N=30005;
      int fa[N], siz[N], dist[N];
       
      int findfa(int x)
      {    
      	if(fa[x]==x)return x;
      
      	int fx=findfa(fa[x]);
      	dist[x]+=dist[fa[x]];
      	return fa[x]=fx;
      }
      
      int hebing(int x,int y)
      {
      	int fx=findfa(x), fy=findfa(y);
      	
      	fa[fy]=fx;
      	dist[fy]=siz[fx];
      	siz[fx]+=siz[fy];	
      }
       
      int main()
      {
      	for(int i=1;i<N;++i) fa[i]=i, siz[i]=1, dist[i]=0;  // 并查集初始化,维护三个值
      	int m; 
      	scanf("%d",&m);
      	while(m--)
      	{
      		int op,x,y;
      		scanf("%d",&op);
      		if(op==1)
      		{
      			scanf("%d%d",&x,&y);
      			hebing(x,y);			
      		}
      		else
      		{
      			scanf("%d",&x);
      			printf("%d\n",siz[findfa(x)]-dist[x]-1);
      		}
      	}
      	return 0;
      }
      
      
      • 1

      信息

      ID
      384
      时间
      1000ms
      内存
      256MiB
      难度
      6
      标签
      (无)
      递交数
      17
      已通过
      11
      上传者