\(n\)个点的完全图,每个点有一个\(C\)为二进制权值\(X_{i}\),$W(u,v) = X_{u} xor X_{v} $
求这个图的最小生成树,支持\(Q\)次修改,每次修改将所有点权值\(+V\),询问具有后效性;
\(1 \le n \le 20000 , C \le 14 , 1 \le Q \le 20000\)
首先答案和\(n\)无关权值只有\(2^C\)中,询问最多也是\(2^C\)种 ,可以预处理所有询问 ;
考虑经典的异或生成树的做法 ;
按照二进制的最高位分治,内部的边比跨越两边的边都要优,在\(Trie\)里查找两两连边的最小值 ;
复杂度:\(O(2^C \times C^22^C)\) ;
对于一个询问\(Q_{i}\),将它分成后\(B\)位和前\(C - B\) 位;
在分治树上,记从下到上为\(0 \to C-1\) 层 ;
$Q_{i} \(后\)C-B\(位的贡献相当于将第\)B$层的分治子树向右整体平移;
\(Q_{i}\)前\(B\)位的贡献相当于只在?\(B\)层之前的叶子平移,对B层以上的结构没有影响;
预处理一个询问的前\(B\)位 确定时\(B\) 层的每个节点分治下去的答案和两两之间合并的答案;
对于后$C - B $位直接分治;
复杂度:\(O( 2^{C+B}B^2 + 2^{2C-B}B)\)
大致\(B\)取\(\frac{n}{2}\)比较好
对前\(B\)层的求解可以再进行优化:
预处理前\(A(A \lt B)\)每个叶子节点的答案和两两之间合并的答案;
考虑到\(A\)比较小,可以直接枚举\(2^{2^{A}}\)颗子树暴力求解,当分治到第\(A\)层时直接调用答案;
复杂度:\(O((2^{2^{A}+1})2^AA \ + \ 2^{2^{A}}2^AA^{2} + 2^{C}2^{B-A}(B-A)^2 \ + \ 2^{2C-A}(B-A) + 2^{2C-B}(C-B)^2)\)
(省略一些近似于常数的东西可能大家的写法有点出入)
这样子\(C==14\)的情况\(A\)取\(3\),\(B\)取\(7\)即可;、
#include<bits/stdc++.h>
#define fir first
#define sec second
#define mk make_pair
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>pii;
int n,q,A,B,C,sum[1<<15],a[1<<15],mask[1<<15];
int v[1<<3],g[1<<8],G[1<<8][1<<8],f[1<<7][1<<7],F[1<<7][1<<7][1<<7],ans[1<<15];
inline int min(int x,int y){return x<y?x:y;}
struct Trie{
int sz,ch[1<<15][2],val[1<<15];
void init(){
for(int i=1;i<=sz;++i)ch[i][0]=ch[i][1]=val[i]=0;
sz=1;
}
void ins(int x,int l,int r,int y){
int now=1;
for(int i=r-1;i>=l;--i){
int t=x>>i&1;
if(ch[now][t])now=ch[now][t];
else ch[now][t]=++sz,now=sz;
}
val[now]=y;
}
pii que(int x,int l,int r){
int res=0,now=1;
for(int i=r-1;i>=l;--i){
int t=x>>i&1;
if(ch[now][t])now=ch[now][t];
else now=ch[now][t^1],res^=1<<i;
}
return mk(res,val[now]);
}
}T;
bool ask(int x,int y){
if(!x)return sum[y-1];
return sum[y-1]-sum[x-1];
}
void init(){
for(int i=0;i<1<<C;++i)a[i+(1<<C)]=a[i];
for(int i=0;i<1<<C+1;++i)sum[i]=sum[i-1]+a[i];
for(int i=0;i<1<<C;++i)
for(int j=0;j<1<<A;++j)mask[i]|=a[i+j]<<j;
for(int i=0;i<1<<C;++i)mask[i+(1<<C)]=mask[i];
}
int solveg(int l,int r){
if(l+1==r)return 0;
int mid=(l+r)>>1,fg;
fg=0;
for(int i=l;i<mid;++i)if(v[i]){fg=1;break;}
if(!fg)return solveg(mid,r);
fg=0;
for(int i=mid;i<r;++i)if(v[i]){fg=1;break;}
if(!fg)return solveg(l,mid);
T.init();
for(int i=l;i<mid;++i)if(v[i])T.ins(i,0,A,i);
int re=inf;
for(int i=mid;i<r;++i)if(v[i])re=min(re,T.que(i,0,A).fir);
return re + solveg(l,mid) + solveg(mid,r);
}
int solvef(const int s,int l,int r){
if(l+1==r)return g[mask[s+(l<<A)]];
int mid=(l+r)>>1,fg;
fg=0;
for(int i=l;i<mid;++i)if(ask(s+(i<<A),s+(i+1<<A))){fg=1;break;}
if(!fg)return solvef(s,mid,r);
fg=0;
for(int i=mid;i<r;++i)if(ask(s+(i<<A),s+(i+1<<A))){fg=1;break;}
if(!fg)return solvef(s,l,mid);
T.init();
for(int i=l;i<mid;++i)if(ask(s+(i<<A),s+(i+1<<A))){
T.ins(i<<A,A,B,s+(i<<A));
}
int re=inf;
for(int i=mid;i<r;++i)if(ask(s+(i<<A),s+(i+1<<A))){
pii r = T.que(i<<A,A,B);
re = min(re, r.fir + G[mask[s+(i<<A)]][mask[r.sec]]);
}
return re + solvef(s,l,mid) + solvef(s,mid,r);
}
int solveans(const int s,int l,int r){
int S1=(1<<B)-1,S2=(1<<C-B)-1;
if(l+1==r)return f[s&S1][l+(s>>B)&S2];
int mid=(l+r)>>1,fg;
fg=0;
for(int i=l;i<mid;++i)if(ask(s+(i<<B),s+(i+1<<B))){fg=1;break;}
if(!fg)return solveans(s,mid,r);
fg=0;
for(int i=mid;i<r;++i)if(ask(s+(i<<B),s+(i+1<<B))){fg=1;break;}
if(!fg)return solveans(s,l,mid);
T.init();
for(int i=l;i<mid;++i)if(ask(s+(i<<B),s+(i+1<<B))){
T.ins(i<<B,B,C,i+(s>>B)&S2);
}
int re=inf;
for(int i=mid;i<r;++i)if(ask(s+(i<<B),s+(i+1<<B))){
pii r = T.que(i<<B,B,C);
re = min(re, r.fir + F[s&S1][i+(s>>B)&S2][r.sec]);
}
return re + solveans(s,l,mid) + solveans(s,mid,r);
}
void calcg(){
for(int i=0;i<1<<(1<<A);++i){
for(int j=0;j<1<<A;++j)v[j]=i>>j&1;
g[i]=solveg(0,1<<A);
}
}
void calcG(){
for(int i=0;i<1<<(1<<A);++i){
T.init();
for(int j=0;j<1<<A;++j)if(i>>j&1){T.ins(j,0,A,j);}
for(int j=0;j<1<<A;++j){G[i][1<<j]=T.que(j,0,A).fir;}
for(int j=0;j<1<<(1<<A);++j){if(j^(j&-j))G[i][j]=min(G[i][j^(j&-j)],G[i][j&-j]);}
}
}
void calcf(){
for(int i=0;i<1<<B;++i)
for(int j=0;j<1<<C-B;++j){
f[i][j]=solvef(i,j<<B-A,j+1<<B-A);
}
}
void calcF(){
for(int i=0;i<1<<B;++i)
for(int j=0;j<1<<C-B;++j){
T.init();
int fg=0;
for(int k=j<<B-A;k<j+1<<B-A;++k)if(ask(i+(k<<A),i+(k+1<<A))){
T.ins(k<<A,A,B,i+(k<<A));fg=1;
}
if(!fg)continue;
for(int k=0;k<1<<C-B;++k){
fg=0;
for(int l=k<<B-A;l<k+1<<B-A;++l)if(ask(i+(l<<A),i+(l+1<<A))){fg=1;break;}
if(!fg){F[i][j][k]=0;continue;}
F[i][j][k]=inf;
for(int l=k<<B-A;l<k+1<<B-A;++l)if(ask(i+(l<<A),i+(l+1<<A))){
pii r=T.que(l<<A,A,B);
F[i][j][k]=min(F[i][j][k], r.fir+G[mask[i+(l<<A)]][mask[r.sec]]);
}
}
}
}
void calcans(){
for(int i=0;i<1<<C;++i)
ans[i]=solveans(i,0,1<<C-B);
}
int main(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
scanf("%d%d",&n,&C);
B=C>>1;A=B>>1;
for(int i=1,x;i<=n;++i)scanf("%d",&x),a[x]=1;
init();
calcg();calcG();
calcf();calcF();
calcans();
scanf("%d",&q);
int S=(1<<C)-1;
for(int i=1,x,y=0;i<=q;++i){
scanf("%d",&x);
y=(y+S+1-x)&S;
printf("%d\n",ans[y]);
}
return 0;
}
原文:https://www.cnblogs.com/Paul-Guderian/p/10533410.html