[2018.12.28]BZOJ4568 [Scoi2016]幸运数字
这种异或和问题一看就是线性基对吧。。。
要维护的是树上两点之间的路径,所以考虑倍增。
发现可以记\(p_{i,j}\)为\(i\)到\(i\)的\(2^j\)次父亲(不含)的点权构出的线性基。
于是我们需要合并两个线性基,记这个操作为\(Merge(p1,p2)\)。
则\(p_{i,j}=Merge(p_{i,j-1},P_{f_{i,j-1},j-1})\)
如何实现?
其实很简单,枚举其中一个线性基中的元素,按照之前构建线性基的方法加入另一个线性基即可。
然后...做完了?!
时间复杂度\(O(qlog^2a_ilogn)\),而且读入/输出的数字规模较大,消耗的时间较多,所以你需要读优。
可能还需要氧气
code:
#include<bits/stdc++.h>
using namespace std;
int n,q,u,v,vis[20010],f[20010][20],dep[20010],pr[20],sz;
long long g[20010],p[20010][20][65],P[65],ans;
vector<int>e[20010];
void scan(long long &x){
char c=getchar();
x=0;
while('0'>c||c>'9')c=getchar();
while('0'<=c&&c<='9')x=x*10+c-'0',c=getchar();
}
void scan(int &x){
char c=getchar();
x=0;
while('0'>c||c>'9')c=getchar();
while('0'<=c&&c<='9')x=x*10+c-'0',c=getchar();
}
void print(long long x){
sz=0;
while(x)pr[++sz]=x%10,x/=10;
while(sz)putchar(pr[sz--]+'0');
}
void Push(long long x,long long *pp){
if(!x)return;
for(int i=60;i>=0;i--){
if(x&(1ll<<i)){
if(!pp[i])pp[i]=x;
x^=pp[i];
}
}
}
void Merge1(long long *p1,long long *p2,long long *mp){
for(int i=60;i>=0;i--)mp[i]=p1[i];
for(int i=60;i>=0;i--)Push(p2[i],mp);
}
void Merge2(long long *p1,long long *mp){
for(int i=60;i>=0;i--)Push(p1[i],mp);
}
void dfs(int x){
vis[x]=1;
for(int i=0;i<e[x].size();i++)
if(!vis[e[x][i]])dep[e[x][i]]=dep[x]+1,dfs(e[x][i]);
else f[x][0]=e[x][i];
}
void LCA_GetP(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=15;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])Merge2(p[x][i],P),x=f[x][i];
for(int i=15;i>=0;i--)if(f[x][i]!=f[y][i])Merge2(p[x][i],P),x=f[x][i],Merge2(p[y][i],P),y=f[y][i];
if(x!=y)Push(g[x],P),Push(g[y],P),Push(g[f[x][0]],P);
else Push(g[x],P);
}
int main(){
scan(n),scan(q);
for(int i=1;i<=n;i++)scan(g[i]),Push(g[i],p[i][0]);
for(int i=1;i<n;i++)scan(u),scan(v),e[u].push_back(v),e[v].push_back(u);
dep[1]=1;
dfs(1);
for(int j=1;j<=15;j++)for(int i=1;i<=n;i++)Merge1(p[i][j-1],p[f[i][j-1]][j-1],p[i][j]),f[i][j]=f[f[i][j-1]][j-1];
while(q--){
scan(u),scan(v);
memset(P,0ll,sizeof(P));
ans=0;
LCA_GetP(u,v);
for(int i=60;i>=0;i--)(ans^P[i])>ans?ans^=P[i]:0;
print(ans),putchar('\n');
}
return 0;
}