对于 x,存在 p,满足 2p⩽x<2p+1,对于所有 ai 按 ⌊ai2p⌋ 的值分组,得每组内的两两异或值都 <x。
然后就只需考虑组与组之间的情况了,将其转化为最小割,源点向第一个组的每个点连容量为 1 的边,第二组的每个点向汇点连容量为 1 的边,两组间异或和 ⩾x 的点对连容量为 ∞ 的边。
直接跑最小割复杂度无法接受,先将最小割转为最大流,对所有权值建立 01 Trie。
设 a0 和 a1 为 a 的左右子树,solve(a,b) 为以 a,b 为根的子树的最大匹配,得:
当 x 在对应深度为 1 时,得其值为 solve(a0,b1)+solve(a1,b0)。
当 x 在对应深度为 0 时,进行分类讨论:
|a0|<|b1|∧|a1|<|b0|⇒|a||a0|>|b1|∧|a1|>|b0|⇒|b||a0|>|b1|∧|a1|<|b0|⇒min(solve(a0,b0),|b0|−|a1|,|a0|−|b1|)+|a1|+|b1||a0|<|b1|∧|a1|>|b0|⇒min(solve(a1,b1),|b1|−|a0|,|a1|−|b0|)+|a0|+|b0|
还需注意 a=b 的情况,设 v0=solve(a0,a0),v1=solve(a1,a1),其值为 v0+v1+min(|a0|−v0,|a1|−v1)。
因为每次修改的节点个数为 O(logn),所以每次询问记忆化即可。
#include<bits/stdc++.h>
#define maxn 100010
#define maxm 10000010
#define s(x,k) siz[ch[x][k]]
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,q,tot=1,root=1;
ll lim;
int ch[maxm][3],siz[maxm],val[maxm],dep[maxm];
ll a[maxn];
bool vis[maxm];
void insert(ll x,int v)
{
int p=root;
siz[p]+=v,dep[p]=60;
for(int i=60;i>=0;--i)
{
int c=(x>>i)&1;
vis[p]=false;
if(!ch[p][c]) ch[p][c]=++tot;
siz[p=ch[p][c]]+=v,dep[p]=i-1;
}
}
int solve(int x,int y)
{
if(!siz[x]||!siz[y]) return 0;
if(vis[x]&&vis[y]) return val[x];
vis[x]=vis[y]=true;
if(dep[x]==-1) return val[x]=min(siz[x],siz[y]);
if((lim>>dep[x])&1) return val[x]=solve(ch[x][0],ch[y][1])+solve(ch[x][1],ch[y][0]);
int v0=solve(ch[x][0],ch[y][0]),v1=solve(ch[x][1],ch[y][1]);
if(x==y) return val[x]=v0+v1+min(s(x,0)-v0,s(x,1)-v1);
if(s(x,0)<=s(y,1)&&s(x,1)<=s(y,0)) return val[x]=siz[x];
if(s(x,0)>=s(y,1)&&s(x,1)>=s(y,0)) return val[x]=siz[y];
if(s(x,0)>=s(y,1)&&s(x,1)<=s(y,0))
return val[x]=min(v0,min(s(y,0)-s(x,1),s(x,0)-s(y,1)))+s(x,1)+s(y,1);
if(s(x,0)<=s(y,1)&&s(x,1)>=s(y,0))
return val[x]=min(v1,min(s(y,1)-s(x,0),s(x,1)-s(y,0)))+s(x,0)+s(y,0);
}
int main()
{
read(n),read(q),read(lim);
for(int i=1;i<=n;++i) read(a[i]),insert(a[i],1);
printf("%d\n",max(n-solve(root,root),1));
while(q--)
{
int x;
read(x),insert(a[x],-1);
read(a[x]),insert(a[x],1);
printf("%d\n",max(n-solve(root,root),1));
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现