Loading

qoj 1168 题解及线性基相关探究

引子:qoj 1168。引子需要的前置知识:P4151

简要题意

给定 \(n\) 个点 \(m\) 条边的无向联通图 \(G\),边有边权。其中 \((u,v)\) 的距离 \(d(u,v)\) 定义为 \(u\to v\) 的最大 \(\text{xor}\) 路径。

\(q\) 次询问 \(l,r\),求 \(\bigoplus\limits_{l\le i<j\le r}d(i,j)\) 的值。

\(1\le n,m,q\le 10^5,0\le w<2^{30}\)

一些转化

首先必然套用 P4151 的结论:设所有环的异或和构成空间为 \(V\)\(d'(u,v)\)\(u\to v\) 的任意一条路径的异或和。

\(d(u,v)=\max\{d'(u,v)\oplus x\mid x\in V\}\)。考虑记变换 \(F_V(x)=\max\{x\oplus a\mid a\in V\},G_V(x)=\min\{x\oplus a\mid a\in V\}\)

\(d(u,v)=F_V(d'(u,v))\),由于一些深刻的理论,我们接下来对 \(F,G\) 的关系进行探究。

线性基上的 min/max 探究

我们给出如下结论:

  • \(F_V(x)\oplus F_V(y)=G_V(x\oplus y)\)

  • \(G_V(x)\oplus G_V(y)=G_V(x\oplus y)\)

  • \(F_V(x)\oplus G_V(y)=F_V(x\oplus y)\)

简而言之:

$\oplus $ \(F\) \(G\)
\(F\) \(F\) \(G\)
\(G\) \(G\) \(F\)

下面证明 \(F\oplus F\to G\),其他同理。下面过程为了迎合 oi 中的线性基算法,可能有少许不严谨。

\(V\) 的线性基的构成元素为 \(B_0,B_1,\cdots,B_L\),但是这里我们令 \(B_L\) 有二进制最高位 \(L\),并把剩下缺的 \(B\) 补齐为 \(0\)

考察 \(F_V(x)\) 运算在 \(L\to 0\) 的每一位中的决策,这对于每一位是一致的,即:

当第 \(k\) 位为 \(0\) 时,异或上 \(B_k\)。当第 \(k\) 位为 \(1\) 时,异或上 \(B_k\)

\(G\) 则是:当第 \(k\) 位为 \(0\) 时,异或上 \(B_k\)。当第 \(k\) 位为 \(1\) 时,异或上 \(B_k\)


我们把 \(F_V(x)\)\(F_V(y)\) 在第 \(k\) 位的决策合并起来:

\(F\oplus F\):当 \(x\oplus y\)\(k\) 位为 \(0\) 时,异或上 \(B_k\)。当第 \(k\) 位为 \(1\) 时,异或上 \(B_k\)

我们就得出了 \(G_V(x\oplus y)\)


更进一步的,显然我们能基于上面三个推出:

\(F^a\oplus G^b\to \begin{cases}G(2\mid a)\\F(2\nmid a)\end{cases}\)

并且,我们注意到 \(G\) 是一个线性变换,即根据 \(G_V(x)\oplus G_V(y)=G_V(x\oplus y)\)。这将很有用。

原题解法

首先容易根据前置知识求出 \(\{a\},V\),其中 \(V\) 为线性基,\(a\) 满足:\(d'(u,v)=a_u \oplus a_v\)

根据上述理论,我们有:\(F_V(x)=F_V(x\oplus 0)=F_V(0)\oplus G_V(x)\)

于是 \(\bigoplus\limits_{l\le i<j\le r}F_V(d'(i,j))=\bigoplus\limits_{l\le i<j\le r}F_V(0)\oplus \bigoplus\limits_{l\le i<j\le r}G_V(d'(i,j))=\bigoplus\limits_{l\le i<j\le r}F_V(0)\oplus G_V\left(\bigoplus\limits_{l\le i<j\le r}d'(i,j)\right)\)

于是单次询问就容易处理了,上个线性基板子即可。

$\texttt{code}$
//qoj 1168
//https://qoj.ac/contest/537/problem/1168
#include<bits/stdc++.h>
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=1e5+5;
struct edge{int to,nex,w;}e[N<<1];
int n,m,q,tot,head[N],B[31],a[N];bool v[N];
inline void add(int u,int v,int w)
{
	e[++tot]={v,head[u],w};head[u]=tot;
	e[++tot]={u,head[v],w};head[v]=tot;
}
inline void ins(int x)
{
	for(int i=30;i>=0;i--)
		if((x>>i)&1)
		{
			if(!B[i]){B[i]=x;break;}
			x^=B[i];
		}
}
inline int que(int x){for(int i=30;i>=0;i--) if((x^B[i])<x) x^=B[i];return x;}
void dfs(int x,int s)
{
	a[x]=s;v[x]=1;
	for(int i=head[x];i;i=e[i].nex)
	{
		int to=e[i].to;
		!v[to]?dfs(to,s^e[i].w):ins(s^a[to]^e[i].w);
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int u,v,w;m--;) scanf("%d%d%d",&u,&v,&w),add(u,v,w);
	dfs(1,0);int mx=0;
	for(int i=30;i>=0;i--) if((mx^B[i])>mx) mx^=B[i];
	for(int i=1;i<=n;i++) a[i]^=a[i-1];
	for(int l,r;q--;)
	{
		scanf("%d%d",&l,&r);int x=r-l,ans=0;
		if(x&1) ans^=que(a[r]^a[l-1]);
		if(((LL)x*(x+1)/2)&1) ans^=mx;printf("%d\n",ans);
	}
	return 0;
}
posted @ 2024-10-25 09:15  HaHeHyt  阅读(40)  评论(0编辑  收藏  举报