2 条题解

  • 1
    @ 2026-8-7 16:42:00

    有矩阵乘法我无疑是兴奋的。

    并查集家族新增一名猛将。

    请先保证这个会了喵:【代码】带权并查集模板-CSDN博客

    // by hansang / proMatheus 
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const LL P = 998244353;
    const int N = 2e5 + 10;
    
    struct Matrix {
    	LL a[2][2];
    	Matrix() {
    		memset(a, 0, sizeof(a));
    	}
    } d[N];
    
    Matrix operator*(Matrix na, Matrix nb) {
    	Matrix nc;
    	for (int k = 0; k <= 1;k ++) {
    		for (int i = 0; i <= 1; i ++) {
    			for (int j = 0; j <= 1; j ++) {
    				nc.a[i][j] = (nc.a[i][j] + na.a[i][k] * nb.a[k][j] % P) % P;
    			}
    		}
    	}
    	return nc;
    }
    
    bool operator==(Matrix na, Matrix nb) {
    	for (int i = 0; i <= 1; i ++) {
    		for (int j = 0; j <= 1; j ++) {
    			if (na.a[i][j] != nb.a[i][j]) {
    				return false;
    			}
    		}
    	}
    	return true;
    }
    
    Matrix get_inv(Matrix no) {
    	Matrix ne;
    	ne.a[0][0] = no.a[1][1];
    	ne.a[0][1] = -no.a[0][1] + P;
    	ne.a[1][0] = -no.a[1][0] + P;
    	ne.a[1][1] = no.a[0][0];
    	return ne;
    }
    
    int fa[N];
    
    int findfa(int x) {
    	if (fa[x] == x) {
    		return fa[x];
    	}
    	int to = findfa(fa[x]);
    	d[x] = d[fa[x]] * d[x];    // 从父亲到孩子,从左到右 
    	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 ++) {   // 阴没边了 base-0 
    		fa[i] = i;
    		for (int j = 0; j <= 1; j ++) {
    			d[i].a[j][j] = 1;   // 单位矩阵 
    		}
    	}
    	
    	while (Q --) {
    		int opt;
    		cin >> opt;
    		int u, v;
    		cin >> u >> v;
    		int fu = findfa(u), fv = findfa(v);
    		
    		if (opt == 0) {
    			Matrix t;
    			for (int i = 0; i <= 1; i ++) {
    				for (int j = 0; j <= 1; j ++) {
    					cin >> t.a[i][j];
    				}
    			}
    			
    			if (fu != fv) {
    				fa[fv] = fu;
    				d[fv] = d[u] * get_inv(t) * get_inv(d[v]);
    				
    				// 关于矩乘等号移位规则:
    				// a * b = c * d 
    				// 右边的移到右边
    				// a * b * d^{-1} = c
    				// a = c * d * c^{-1}
    				// 左边移到左边 
    				// c^{-1} * a * b = d
    				// b = a^{-1} * c * d
    				// 反正记住乘号两边不能随意换位置就是了 
    				
    				// d[u] = d[v] * t 
    				// 这里的 fv 因为还是并查集的头目,所以 d[fv] 是单位矩阵
    				// 我们通过 d[u] 和 d[v] 的关系重塑 d[fv] 
    				// d[fv] = d[u] * t^{-1} * d[v]^{-1}
    				
    				// 从左到右执行:
    				// 第 1 步:应用反向约束,从 u 到 v  
    				// 第 2 步:撤销 d[v] 的贡献,从 v 到 v 的根 fv 
    				// 为什么是这个顺序?
    		// 因为 d[fv] * d[v] * t = d[fu](这玩意是单位矩阵要不要都行) * d[u] 
    				// 你把等式左边的从右到左,按照移位规则移到右边去
    				 
    				cout << "1\n";
    			}
    			else {
    				if (d[v] * t == d[u]) {
    					cout << "1\n";
    				}
    				else {
    					cout << "0\n";
    				}
    			}
    		}
    		else {
    			if (fu != fv) {
    				cout << "-1\n";
    			}
    			else {
    				// d[u] = d[v] * t 
    				// d[v]^{-1} * d[u] = t
    				Matrix t = get_inv(d[v]) * d[u];
    				for (int i = 0; i <= 1; i ++) {
    					for (int j = 0; j <= 1; j ++) {
    						cout << t.a[i][j] << " ";
    					}
    				}
    				cout << "\n";
    			}
    		}
    	}
    	
    	return 0;
    } 
    
    
    • 0
      @ 2025-12-8 19:26:04
      #include<bits/stdc++.h>
      using namespace std;
      #define int long long
      #define N 200010
      #define mod 998244353
      //a b
      //c d
      struct node{
      	int a,b,c,d;
      };
      bool operator==(node n1,node n2){
      	return n1.a==n2.a
      		 &&n1.b==n2.b
      		 &&n1.c==n2.c
      		 &&n1.d==n2.d;
      }
      node operator*(node n1,node n2){
      	return (node){
      		(n1.a*n2.a+n1.b*n2.c)%mod,
      		(n1.a*n2.b+n1.b*n2.d)%mod,
      		(n1.c*n2.a+n1.d*n2.c)%mod,
      		(n1.c*n2.b+n1.d*n2.d)%mod
      	};
      }
      node change(node n1){
      	return {n1.d,-n1.b+mod,-n1.c+mod,n1.a};
      }
      int n,q,fa[N];
      node d[N];
      int findfa(int x){
      	if(fa[x]!=x){
      		int top=findfa(fa[x]);
      		d[x]=d[fa[x]]*d[x];
      		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]={1,0,0,1};
      	while(q--){
      		int op;cin>>op;
      		if(op==0){
      			int x,y,A,B,C,D;cin>>x>>y>>A>>B>>C>>D;
      			node a={A,B,C,D};
      			int tx=findfa(x),ty=findfa(y);
      			if(tx!=ty){
      				fa[ty]=tx;
      				d[ty]=d[x]*change(a)*change(d[y]);
      				cout<<"1\n";
      			}
      			else{
      				if(change(d[y])*d[x]==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{
      				node ans=change(d[y])*d[x];
      				cout<<ans.a<<' '<<ans.b<<' '<<ans.c<<' '<<ans.d<<'\n';
      			}
      		}
      	}
      	
      	return 0;
      }
      
      • 1

      带权并查集(非交换群)(Unionfind with Potential (Non-Commutative Group))

      信息

      ID
      8122
      时间
      1000ms
      内存
      1024MiB
      难度
      7
      标签
      递交数
      44
      已通过
      9
      上传者