3 条题解

  • 1
    @ 2026-8-2 11:17:28

    带权并查集,核心思想就是将边权下放到点上,从而利用类似于前缀和的思想快速求出两点间的边权,核心难点便是连边时权值的处理方式。

    对于这道题,我们先不考虑取模的问题,直接假定题目给出的是 av=au+ka_v=a_u+k(看清楚 uuvv),那么假设 disxdis_xxx 到它所在的树的根节点的边权之和。显然,对于同一颗树内的任意两点 u,vu,v,对于 u>vu->v 这条边的边权 kk,必然有 k+disv=disuk+dis_v=dis_u,则 k=disudisvk=dis_u-dis_v

        root
     5/  1  \4
     u  - >  v
    

    接下来考虑两颗不同树内的节点 u,vu,v,分别找到根 a,ba,b。从 bbaa 连一条边权为 xx 的边(aabb 也可以),接下来,我们假设从 uubb 连一条边,易得这条边的边权为 k+disvk+dis_v,所以有 k+disv+x=disuk+dis_v+x=dis_u,所以 x=disukdisvx=dis_u-k-dis_v

          5-1-2
      a<---------b
      ^          ^
      |         /|
      |        / |
      |       /  |
      |      /   |
     5|  1+2/    |2
      |    /     |
      |   /      |
      |  /       |
      | /        |
      |/         |
      u--------->v
            1
    

    在此题中,记得取模就行。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const long long mod=998244353;
    long long dis[200005];
    int fa[200005];
    int find(int x){
    	if(fa[x]==x){
    		return x;
    	}
    	int to=find(fa[x]);
    	dis[x]=(dis[x]+dis[fa[x]])%mod;
    	return fa[x]=to;
    }
    int main(){
    	int n,q;
    	cin>>n>>q;
    	for(int i=0;i<n;i++){
    		fa[i]=i;
    	}
    	while(q--){
    		int op;
    		cin>>op;
    		if(op==0){
    			long long u,v,k;
    			cin>>u>>v>>k;
    			int a=find(u),b=find(v);
    			if(a!=b){
    				fa[b]=a;
    				dis[b]=(dis[u]-dis[v]-k+mod*3)%mod;
    				cout<<1<<"\n";
    			}
    			else{
    				if((dis[u]-dis[v]+mod*2)%mod==k){
    					cout<<1<<"\n";
    				}
    				else{
    					cout<<0<<"\n";
    				}
    			}
    		}
    		else{
    			int u,v;
    			cin>>u>>v;
    			int a=find(u),b=find(v);
    			if(a!=b){
    				cout<<"-1\n";
    			}
    			else{
    				cout<<(dis[u]-dis[v]+mod*2)%mod<<"\n";
    			}
    		}
    	}
    	return 0;
    }
    
    • 0
      @ 2026-8-6 10:31:38

      放个注释代码喵

      #include<bits/stdc++.h>
      using namespace std;
      
      typedef long long LL;
      const LL P = 998244353;
      const int N = 2e5 + 10;
      
      LL dis[N];
      int fa[N];
      
      int findfa(int x) {
      	if (x == fa[x]) {
      		return fa[x];
      	}
      	int to = findfa(fa[x]);
      	dis[x] = (dis[x] + dis[fa[x]]) % P;
      	return fa[x] = to;
      } 
      
      int main () {
      	ios::sync_with_stdio(false);
      	cin.tie(0);
      	
      	int n, Q;
      	cin >> n >> Q;
      	for (int i = 0; i < n; i ++) {
      		fa[i] = i;
      		dis[i] = 0;
      	}
      	
      	while (Q --) {
      		int opt;
      		cin >> opt;
      		if (opt == 0) {
      			int u, v; LL k;
      			cin >> u >> v >> k;
      			// a[u] = a[v] + k
      			// a[u] - a[v] = k 
      			int fu = findfa(u), fv = findfa(v);
      			if (fu != fv) {
      				fa[fv] = fu;
      				
      				// dis[u] = a[fu] - a[u]
      				// dis[v] = a[fv] - a[v]
      				// a[fu] - a[fv] = dis[u] - a[u] - dis[v] + a[v] 
      				dis[fv] = (dis[u] - dis[v] - k + 3 * P) % P;
      				cout << "1\n";
      			}
      			else {
      				if ((dis[u] - dis[v] + 2 * P) % P == k) {
      					cout << "1\n";
      				}
      				else {
      					cout << "0\n";
      				}
      			}
      		}
      		else {
      			int u, v;
      			cin >> u >> v;
      			int fu = findfa(u), fv = findfa(v);
      			if (fu != fv) {
      				cout << "-1\n";
      			}
      			else {
      				cout << (dis[u] - dis[v] + 2 * P) % P << "\n";
      			}
      		}
      	}
      	
      	return 0;
      } 
      
      
      • 0
        @ 2025-12-8 18:36:56
        #include<bits/stdc++.h>
        using namespace std;
        #define int long long
        #define pii pair<int,int>
        #define fi first
        #define se second
        #define N 200010
        #define mod 998244353
        int n,q,fa[N],d[N];
        int findfa(int x){
        	if(fa[x]!=x){
        		int top=findfa(fa[x]);
        		d[x]=(d[x]+d[fa[x]])%mod;
        		fa[x]=top;
        	}
        	return fa[x];
        }
        signed main(){
        	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
        	cin>>n>>q;
        	for(int i=0;i<n;i++)fa[i]=i,d[i]=0;
        	while(q--){
        		int op;cin>>op;
        		if(op==0){
        			int x,y,a;cin>>x>>y>>a;
        			a=(a%mod+mod)%mod;
        			int tx=findfa(x),ty=findfa(y);
        			if(tx!=ty){
        				fa[ty]=tx;
        				d[ty]=((d[x]-d[y]-a)%mod+mod)%mod;
        				cout<<"1\n";
        			}
        			else{
        				if(((d[x]-d[y])%mod+mod)%mod==a)cout<<"1\n";
        				else cout<<"0\n";
        			}
        		}
        		else{
        			int x,y;cin>>x>>y;
        			int tx=findfa(x),ty=findfa(y);
        			if(tx!=ty){
        				cout<<"-1\n";
        			}
        			else{
        				cout<<((d[x]-d[y])%mod+mod)%mod<<'\n';
        			}
        		}
        	}
        	
        	return 0;
        }
        
        • 1

        带权并查集(Unionfind with Potential)

        信息

        ID
        8121
        时间
        1000ms
        内存
        1024MiB
        难度
        7
        标签
        递交数
        76
        已通过
        17
        上传者