题目
描述:
(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 imes C^22^C)) ;
-
算法二:
-
对于一个询问(Q_{i}),将它分成后(B)位和前(C - B) 位;
-
在分治树上,记从下到上为(0 o 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 ",ans[y]); } return 0; }