【提单】wzy

题单:https://vjudge.net/article/18015

T1

参考最大XOR和路径问题,我们从环考虑,发现所有的环都能拆成一条边自己走的环和生成树上连了一条边的环,然后动态用线性基维护这个东西,难点在于如何维护k进制线性基。

插入跟二进制没区别,不过需要辗转相减,因为不一定能完全消掉,然后查询的时候,由于我们要异或和最大,我们看一下每一位需要加多少,这个怎么做呢?如果是二进制,直接加一次就行了,但是k进制需要加很多次,怎么判断最值以及次数呢?根据裴蜀定理,\(B_{i,i}\)的若干倍\(\bmod k\)能取到 \(y=\gcd(B_{i,i},k)\) 的所有倍数,所以当前最小值就是 \(x[i]%y\),减去了 \(z=x[i]/y\)\(y\),那么减去了多少个 \(B_{i,i}\) 呢,这个可以用exgcd求出多少个 \(B_{i,i}\) 能凑出 \(y\),然后乘以 \(z\) 就行了。还有一个问题,注意到这个东西,不仅仅能对主元有贡献,还对低位有贡献,因为跟二进制不一样,有可能有方案这一位相同但是低位不同,所以查询前要把每一位的主元消掉然后再插一遍,算出低位的贡献。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
using arr=array<int,30>;
namespace IO{
#define gc getchar
#define pc putchar
#define ps puts
	inline int in(){
		int x=0,f=1;
		char c=gc();
		for(;!isdigit(c);c=gc())if(c=='-')f=-1;
		for(;isdigit(c);c=gc())x=x*10+(c-'0');
		return x*f;
	}
	inline void out(int x){
		if(x<0)pc('-'),x=-x;
		if(x>=10)out(x/10);
		pc(x%10+'0');
	}
	inline void outsp(int x){out(x),pc(' ');}
	inline void outln(int x){out(x),ps("");}
}
using namespace IO;
const int N=2e5+5;
int q,k,n=1,m;
arr b[30],d[N];
arr A(int x){
	arr y;
	for(int i=0;i<=m;i++)y[i]=x%k,x/=k;
	return y;
}
int I(arr x){
	int y=0;
	for(int i=m;i>=0;i--)y=y*k+x[i];
	return y;
}
arr operator +(arr x,arr y){
	for(int i=0;i<=m;i++)x[i]=(x[i]+y[i])%k;
	return x;
}
arr operator -(arr x,arr y){
	for(int i=0;i<=m;i++)x[i]=(x[i]-y[i]+k)%k;
	return x;
}
arr operator *(arr x,int y){
	for(int i=0;i<=m;i++)x[i]=x[i]*y%k;
	return x;
}
void exgcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return;}
	exgcd(b,a%b,y,x),y-=a/b*x;
}
void ins(arr x){
	for(int i=m;i>=0;i--)if(x[i]){
		if(!b[i][i]){b[i]=x;break;}
		while(x[i])b[i]=b[i]-x*(b[i][i]/x[i]),swap(b[i],x);
	}
}
arr query(arr x){
	for(int i=m;i>=0;i--)if(b[i][i]){
		int y=__gcd(b[i][i],k),z=x[i]/y,X,Y;
		exgcd(b[i][i],k,X,Y),X=(X%k+k)%k*z%k;
		x=x-b[i]*X;
	}
	return x;
}
signed main(){
	q=in(),k=in(),m=in()-1;
	while(q--){
		int op=in();
		if(op==1){
			int u=in();
			arr x=A(in());
			d[++n]=d[u]+x,ins(x*2);
		}
		if(op==2){
			int u=in(),v=in();
			arr x=A(in());
			ins(d[u]+x+d[v]);
		}
		if(op==3){
			int u=in(),v=in();
			for(int i=0;i<=m;i++)ins(b[i]*(k/__gcd(b[i][i],k)));
			outln(I(query(d[u]+d[v])));
		}
	}
	return 0;
}
posted @ 2026-05-20 18:15  Lqs314  阅读(5)  评论(0)    收藏  举报