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

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

简要题意#

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

q 次询问 l,r,求 li<jrd(i,j) 的值。

1n,m,q105,0w<230

一些转化#

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

d(u,v)=max{d(u,v)xxV}。考虑记变换 FV(x)=max{xaaV},GV(x)=min{xaaV}

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

线性基上的 min/max 探究#

我们给出如下结论:

  • FV(x)FV(y)=GV(xy)

  • GV(x)GV(y)=GV(xy)

  • FV(x)GV(y)=FV(xy)

简而言之:

F G
F F G
G G F

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

V 的线性基的构成元素为 B0,B1,,BL,但是这里我们令 BL 有二进制最高位 L,并把剩下缺的 B 补齐为 0

考察 FV(x) 运算在 L0 的每一位中的决策,这对于每一位是一致的,即:

当第 k 位为 0 时,异或上 Bk。当第 k 位为 1 时,异或上 Bk

G 则是:当第 k 位为 0 时,异或上 Bk。当第 k 位为 1 时,异或上 Bk


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

FF:当 xyk 位为 0 时,异或上 Bk。当第 k 位为 1 时,异或上 Bk

我们就得出了 GV(xy)


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

FaGb{G(2a)F(2a)

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

原题解法#

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

根据上述理论,我们有:FV(x)=FV(x0)=FV(0)GV(x)

于是 li<jrFV(d(i,j))=li<jrFV(0)li<jrGV(d(i,j))=li<jrFV(0)GV(li<jrd(i,j))

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

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 @   HaHeHyt  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2023-10-25 竞赛图性质研究(强联通分量/哈密顿回路)
点击右上角即可分享
微信分享提示
主题色彩
主题色彩