Description
有一张n个点的完全图,每个点有点权xi,边(i,j)的边权为xi xor xj
有q组询问,每次询问给出v,问将所有点权加上v对2^c-1取模之后这张图的最小生成树
n,q<=20000,c<=14
Solution
EricHuang出的神仙题 Orz
首先n和q的范围都只有2^c-1,复杂度只和c有关
然后这个暴力相信大家都会,是经典的异或生成树,是建trie然后分治
考虑折半,将询问变为[0,B),[B,C)这两段,如果我们预处理出所有
2
B
2^B
2B种前半段的询问中, 所有深度为
2
C
−
B
2^{C-B}
2C−B的子树内部的答案以及两两匹配的结果,我们就可以用
2
C
−
B
2^{C-B}
2C−B的复杂度做一次询问,询问的复杂度是
O
(
2
2
C
−
B
C
2
)
O(2^{2C-B}C^2)
O(22C−BC2)
考虑这个预处理怎么做,可以再折半,考虑变为[0,A),[A,B)这两段,注意到A不会很大,最下面A层总共可能有
2
2
A
2^{2^A}
22A种不同的子树,我们可以对于每一种子树都暴力求答案并且两两匹配的结果,这里是
O
(
2
2
A
+
1
2
2
A
+
2
2
A
2
A
A
2
)
O(2^{2^{A+1}}2^{2A}+2^{2^A}2^{A}A^2)
O(22A+122A+22A2AA2)的
接下来我们枚举每个
2
B
2^B
2B的询问和每个
2
C
−
B
2^{C-B}
2C−B的子树,然后往上合并,这里是
O
(
2
2
C
−
B
(
B
−
A
)
2
)
O(2^{2C-B}(B-A)^2)
O(22C−B(B−A)2)的
然后枚举两个深度为
2
C
−
B
2^{C-B}
2C−B的子树匹配,这里是
O
(
2
2
C
−
A
(
B
−
A
)
)
O(2^{2C-A}(B-A))
O(22C−A(B−A))的
然后就做完了,注意到C很小我们可以直接取B=C/A,A=B/2
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define mp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pr;
const int N=(1<<15)+5,M=(1<<8)+5;
int n,A,B,C,x,q,a[N],sum[N],mask[N],m,v[M];
struct Trie{
int son[N<<4][2],val[N<<4],tot;
void clear() {
fo(i,1,tot) son[i][0]=son[i][1]=val[i]=0;
tot=1;
}
void insert(int v,int l,int r,int id) {
int x=1;
fd(i,r-1,l) {
int y=v>>i&1;
if (!son[x][y]) son[x][y]=++tot;
x=son[x][y];
}
val[x]=id;
}
pr query(int v,int l,int r) {
int x=1,tmp=0;
fd(i,r-1,l) {
int y=v>>i&1;
if (son[x][y]) x=son[x][y];
else x=son[x][1-y],tmp+=1<<i;
}
return mp(tmp,val[x]);
}
}tr;
int h[M],H[M][M];
bool empty(int l,int r) {return l?!(sum[r]-sum[l-1]):!sum[r];}
int solveh(int l,int r) {
if (l==r) return 0;
int mid=l+r>>1,ret=m,in=0;
fo(i,l,mid) in|=v[i];if (!in) return solveh(mid+1,r);
in=0;fo(i,mid+1,r) in|=v[i];if (!in) return solveh(l,mid);
tr.clear();
fo(i,l,mid) if (v[i]) tr.insert(i,0,A,i);
fo(i,mid+1,r) if (v[i]) ret=min(ret,tr.query(i,0,A).first);
return ret+solveh(l,mid)+solveh(mid+1,r);
}
void solve_h() {
fo(i,0,(1<<(1<<A))-1) {
fo(j,0,(1<<A)-1) v[j]=i>>j&1;
h[i]=solveh(0,(1<<A)-1);
}
fo(i,1,(1<<(1<<A))-1)
fo(j,1,(1<<(1<<A))-1) {
H[i][j]=m;
fo(k,0,(1<<A)-1) fo(l,0,(1<<A)-1)
if ((i>>k&1)&&(j>>l&1))
H[i][j]=min(H[i][j],k^l);
}
}
int solveg(int s,int l,int r) {
if (l==r) return h[mask[s+(l<<A)]];
int mid=l+r>>1,ret=m,in=0;
fo(i,l,mid) in|=!empty(s+(i<<A),s+(i<<A)+(1<<A)-1);
if (!in) return solveg(s,mid+1,r);
in=0;fo(i,mid+1,r) in|=!empty(s+(i<<A),s+(i<<A)+(1<<A)-1);
if (!in) return solveg(s,l,mid);
tr.clear();
fo(i,l,mid) if (!empty(s+(i<<A),s+(i<<A)+(1<<A)-1))
tr.insert(i<<A,A,B,s+(i<<A));
fo(i,mid+1,r) if (!empty(s+(i<<A),s+(i<<A)+(1<<A)-1)) {
pr tmp=tr.query(i<<A,A,B);
ret=min(ret,tmp.first+H[mask[tmp.second]][mask[s+(i<<A)]]);
}
return ret+solveg(s,l,mid)+solveg(s,mid+1,r);
}
int g[M][M],G[M][M][M];
void solve_g() {
fo(i,0,(1<<B)-1)
fo(j,0,(1<<C-B)-1)
g[i][j]=solveg(i,j<<B-A,(j<<B-A)+(1<<B-A)-1);
fo(i,0,(1<<B)-1)
fo(j,0,(1<<C-B)-1) {
if (empty(i+(j<<B),i+(j<<B)+(1<<B)-1)) continue;
tr.clear();
fo(k,0,(1<<B-A)-1)
if (!empty(i+(j<<B)+(k<<A),i+(j<<B)+(k<<A)+(1<<A)-1))
tr.insert((j<<B)+(k<<A),A,B,i+(j<<B)+(k<<A));
fo(k,0,(1<<C-B)-1) {
if (empty(i+(k<<B),i+(k<<B)+(1<<B)-1)) continue;
if (j==k) continue;
G[i][j][k]=m;
fo(l,0,(1<<B-A)-1)
if (!empty(i+(k<<B)+(l<<A),i+(k<<B)+(l<<A)+(1<<A)-1)) {
pr tmp=tr.query((k<<B)+(l<<A),A,B);
G[i][j][k]=min(G[i][j][k],tmp.first+H[mask[tmp.second]][mask[i+(k<<B)+(l<<A)]]);
}
}
}
}
int solvef(int s1,int s2,int l,int r) {
int S=(1<<C-B)-1;
if (l==r) return g[s1][(l+s2)&S];
int mid=l+r>>1,ret=m,in=0,s=s1+(s2<<B);
fo(i,l,mid) in|=!empty(s+(i<<B),s+(i<<B)+(1<<B)-1);
if (!in) return solvef(s1,s2,mid+1,r);
in=0;fo(i,mid+1,r) in|=!empty(s+(i<<B),s+(i<<B)+(1<<B)-1);
if (!in) return solvef(s1,s2,l,mid);
tr.clear();
fo(i,l,mid)
if (!empty(s+(i<<B),s+(i<<B)+(1<<B)-1))
tr.insert(i<<B,B,C,i);
fo(i,mid+1,r)
if (!empty(s+(i<<B),s+(i<<B)+(1<<B)-1)) {
pr tmp=tr.query(i<<B,B,C);
ret=min(ret,tmp.first+G[s1][(i+s2)&S][(tmp.second+s2)&S]);
}
return ret+solvef(s1,s2,l,mid)+solvef(s1,s2,mid+1,r);
}
int f[N];
void solve_f() {
fo(i,0,(1<<B)-1)
fo(j,0,(1<<C-B)-1)
f[i+(j<<B)]=solvef(i,j,0,(1<<C-B)-1);
}
void prepare() {
fo(i,0,m) a[i+(1<<C)]=a[i];
sum[0]=a[0];fo(i,1,1<<C<<1) sum[i]=sum[i-1]+a[i];
fo(i,0,m) fo(j,0,(1<<A)-1) mask[i]|=a[i+j]<<j;
fo(i,0,m) mask[i+(1<<C)]=mask[i];
}
int main() {
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
scanf("%d%d",&n,&C);
fo(i,1,n) {
scanf("%d",&x);
a[x]=1;
}
B=C>>1;A=B>>1;m=(1<<C)-1;
prepare();
solve_h();solve_g();solve_f();
int sum=0;
for(scanf("%d",&q);q;q--) {
scanf("%d",&x);sum=(sum+x)&m;
printf("%d\n",f[(m+1-sum)&m]);
}
return 0;
}