线性基小计

引入

很早就听说这个高大上的算法了,好像很厉害的样子。
但是 blog 里说的是异或线性基 不是线性代数那个那个看不懂

线性基用来干什么?

  • 查询一个数能不能被一堆数异或出来
  • 查询一堆数异或的最大值
  • 查询异或第 k 大 / 小 (本质不同)

概念

线性基有 3 个性质。

  • 原序列任意数以及任意一堆数的异或可以通过线性基异或出来
  • 线性基任意数异或起来不会产生 0
  • 满足上述条件时,使得线性基内数最少。

构造

怎么构造一个满足上述条件的线性基呢?
这要扯到线性代数方面,我不好说。
不如直接感性理解。

怎么使得线性基数的个数最小?

我们假设现在已经插入了 a1,a2,a3,a4 现在插入 a5
怎么办呢?
假设 a5 很大,不好插入。
根据异或的性质,实际上,插入 a5a1 或者 a5a2a3 是等价 a5 的。

明显的,这些数插入都会产生相同的线性基。
那么,我们是不是可以在原有 a1,a2,a3,a4 的前提下,构造出一个合法的,最小的 a5 插入呢?

线性基的插入

根据上面的思想,我们可以以这样思考:
令最终线性基为 d ,其中 di 是第 i 位线性基内存的数,满足最高位是第 i 位。
明显的,这个线性基的大小不会超过 logv

我们思考怎么插入一个数:
不妨令 a1,a2,a3,a4 已经构造出一个 d,现在插入 a5
从大到小枚举 i 。如果 a5i 位为 1,分类讨论:

  • di 为空。这时直接插入,退出。
  • 否则令 a5=a5di 继续遍历。

第一个操作好理解,第二个呢?
根据我们刚才的分析,现在的 i 肯定是 a5 的最高位。

这一位无法插入,我们考虑插入一个和 a5 等价的,也许是 a5a3 ,然后把这一位删除,考虑下一位。

不妨考虑这样有什么后果。

  • 找到下一位为空的 di
  • 找不到为空的 di

第一种情况直接就结束了,我们考虑情况 2
找不到为空的 di ,可以证明,现在 a5=0 因为我们已经从小到大把 a5 所有位数都给删掉了。

这说明,我们可以在 a1,a2,a3,a4 中构造出一种异或,使得它们的异或和为 a5
这时候,a5 不需要插入。

这样,我们构造出了满足 1,2 的线性基。

因为线性基内的数总是小于原数组的数,所以 3 也满足。
因此,构造完毕。

异或最值

Max

很简单,因为每一位线性基最高位是确定的,从后往前贪心即可。

Min

根据每一位是确定的,从前往后找到第一个有数的基即可。

Kth

不会bx

前缀线性基

link
考虑两种写法。
无脑分制很简单,这不讲了。

我们考虑前缀线性基。
明显,我们可以把所有时候,定义状态 fi 表示 [1,i] 的线性基,并且满足每一位最大。
这怎么搞?
一种显然的想法,从第 i 为开始往后插入。
但是这不好搞,时间不允许。
假设我们已经求出 [1,i1] 满足每一位最大。
现在我们插入 i
考虑第 i 位肯定是要插入的。我们要把哪一位取出来。
根据贪心,后面的取出来可以从前面插入。
如果前面插入不了了,那这一位肯定要插入进去,如果大可以在后面考虑。可以发现此时插入一定不劣。

我们可以理解为把这一位基拿出来,然后塞进去,得到一个同等的子问题,但是 pos 变小。后面 pos 贪心搞即可。

  • 例题
    P3292
    你不会写没关系,淀粉质直接薄纱 dijah 前缀线性基做法,知不知道 O(nlog2n) 快过理论 O(nlogn) 轰啊
点击查看代码
#include<bits/stdc++.h>
#define N 20005
#define ll long long
using namespace std;
int n,m;
int head[N],tot=1;
struct edge{
	int to,next;
}e[N*2];
void add(int u,int v)
{
	e[tot]=(edge){v,head[u]};
	head[u]=tot++;
}
ll w[N],ans[N*10];
struct node{
	int x,id;	
};
vector<node> q[N];
int root,minn;
int siz[N],vis[N];
struct Xor{
	ll d[62];
	void insert(ll x)
	{
		for(int i=60;i>=0;i--)
			if(x&(1ll<<i)) 
				if(d[i]) x^=d[i];
				else {d[i]=x;return ;}
	}
	ll ask()
	{
		ll sum=0;
		for(int i=60;i>=0;i--)
			sum=max(sum,sum^d[i]);
		return sum;
	}
}f[N];
Xor merges(Xor a,Xor b)
{
	for(int i=0;i<=60;i++)
		if(a.d[i]) b.insert(a.d[i]);
	return b; 
}
void groot(int now,int fa,int n)
{
	int maxx=0;
	siz[now]=1;
	for(int i=head[now];i;i=e[i].next)
	{
		int son=e[i].to;
		if(son==fa||vis[son]) continue;
		groot(son,now,n);
		siz[now]+=siz[son];
		maxx=max(maxx,siz[son]);
	}
	maxx=max(maxx,n-siz[now]);
	if(maxx<minn) minn=maxx,root=now;
}
int col[N],ids;
void getdis(int now,int fa)
{
	col[now]=ids;
	f[now]=f[fa],f[now].insert(w[now]); 
	siz[now]=1;
	for(int i=head[now];i;i=e[i].next)
	{
		int son=e[i].to;
		if(son==fa||vis[son]) continue;
		getdis(son,now);
		siz[now]+=siz[son];
	}
}
void getans(int now,int fa)
{
	for(int i=0;i<q[now].size();i++)
		if(col[q[now][i].x]^col[now])
		{
			ans[q[now][i].id]=merges(f[now],f[q[now][i].x]).ask();
			swap(q[now][i],q[now][q[now].size()-1]);
			q[now].pop_back();
			i--;
		}
	for(int i=head[now];i;i=e[i].next)
	{
		int son=e[i].to;
		if(son==fa||vis[son]) continue;
		getans(son,now);
	}
}
void solve(int now,int n)
{
	minn=n+2;
	groot(now,0,n);
	vis[root]=1;
	memset(f[root].d,0,sizeof f[root].d);
	f[root].insert(w[root]);
	col[root]=ids=0;
	for(int i=head[root];i;i=e[i].next)
	{
		int son=e[i].to;
		if(vis[son]) continue;
		++ids;
		getdis(son,root);
	}
	getans(root,0);
	for(int i=head[root];i;i=e[i].next)
	{
		int son=e[i].to;
		if(vis[son]) continue;
		solve(son,siz[son]);
	}
}
int main()
{
//	freopen("c.in","r",stdin);
//	freopen("m.txt","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		if(u^v) q[u].push_back((node){v,i});
		else ans[i]=w[u];
	}
	solve(1,n);
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
}

求有多少个数比 x

使用贪心。
把每一位线性基里面的数拿出来。
如果 x 这一位是 1 且 存在 d 这一位也是 1

那么我们把 前面有的位数全取了,后面随便取即可。
否则退出。

posted @   g1ove  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示