版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/85568253
BZOJ传送门
洛谷传送门
解析:
第一眼倍增+线性基合并
,复杂度过不了。
第二眼树分块+线性基合并
,复杂度过不了。
算了写点分治吧。。。
思路:
子集最大异或和,显然线性基。
线性基的合并似乎也没有什么快的算法,就暴力合并吧,
要是倍增再来一个 就真GG了。
所以我们不用倍增,考虑怎么拼出一条路径,对,点分治。
复杂度期望 ,不过好像最坏情况也是这个,我就不证明了。
每次选择一个重心,处理出当前联通块中所有点到它的路径的线性基。
然后所有在这个联通块里面的询问,看是否两个端点不在同一个子树内部。不在的话就可以合并它们的线性基,不需要担心根节点权值的问题,因为一个线性基里面多次插入一个值是不会有任何影响的。
然后直接在线性基里面查询最大值。直接从最高位贪心做就行了。
实际实现的时候我加了很多剪枝,不过很多似乎没优化啊。。。
UPD:
去看了一下题解,几乎全部都是倍增。。。
是这数据真是水的可以,还是我的复杂度分析错了啊。。。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1,*p2;
char obuf[Rlen],*p3=obuf;
char ch[23];
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline void put_char(char c){
using namespace IOONLY;
*p3++=c;
if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
}
inline void FLUSH(){
using namespace IOONLY;
fwrite(obuf,1,p3-obuf,stdout),p3=obuf;
}
inline ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline void outint(ll a){
using namespace IOONLY;
if(a==0)return pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
}
using namespace IO;
namespace Linear_base{
inline void clear(ll f[]){
memset(f,0,sizeof(ll)*61);
}
inline void copy(ll g[],ll f[]){
memcpy(g,f,sizeof(ll)*61);
}
inline void insert(ll f[],ll a){
for(int re i=60;~i;--i){
if(a&(1ll<<i)){
if(!f[i]){
f[i]=a;
return ;
}
a^=f[i];
if(a==0)return ;
}
}
}
inline void merge(ll g[],ll f1[],ll f2[]){
copy(g,f1);
for(int re i=60;~i;--i){
if(f2[i]&&(f2[i]^f1[i])&&(f2[i]^g[i]))insert(g,f2[i]);
}
}
inline ll query(ll f[],ll res=0){
for(int re i=60;~i;--i)if((res^f[i])>res)res^=f[i];
return res;
}
}
cs int N=20004,Q=200005,B=61;
vector<int> edge[N];
inline void addedge(int u,int v){
edge[v].push_back(u);
edge[u].push_back(v);
}
ll g[N];
int last[N],nxt[Q<<1],to[Q<<1],qcnt=1;
bool have[Q];ll ans[Q];
inline void addq(int u,int v){
nxt[++qcnt]=last[u],last[u]=qcnt,to[qcnt]=v;
nxt[++qcnt]=last[v],last[v]=qcnt,to[qcnt]=u;
if(u==v)have[qcnt>>1]=true,ans[qcnt>>1]=g[u];
}
int n,q;
bool ban[N];
int que[N],siz[N],tail;
int total,mx,G;
inline void find_G(int u,int fa){
while(last[u]&&have[last[u]>>1])last[u]=nxt[last[u]];
if(last[u])que[++tail]=u;
siz[u]=1;int maxn=1;
for(int re e=0;e<edge[u].size();++e){
if(ban[edge[u][e]])continue;
if(edge[u][e]^fa){
find_G(edge[u][e],u);
siz[u]+=siz[edge[u][e]];
maxn=max(maxn,siz[edge[u][e]]);
}
}
maxn=max(maxn,total-siz[u]);
if(mx>=maxn){
mx=maxn;
G=u;
}
}
int group[N],tsiz[N];;
ll res[B],f[N][B];
inline void dfs(int u,int fa,cs int &bel){
if(!tsiz[u])return ;
group[u]=bel;
Linear_base::copy(f[u],f[fa]);
Linear_base::insert(f[u],g[u]);
for(int re e=0;e<edge[u].size();++e){
if(ban[edge[u][e]])continue;
if(edge[u][e]^fa)dfs(edge[u][e],u,bel);
}
}
inline void dfs_q(int u,int fa){
if(last[u])tsiz[u]=1;
else tsiz[u]=0;
for(int re e=0;e<edge[u].size();++e)
if(!ban[edge[u][e]]&&(edge[u][e]^fa))dfs_q(edge[u][e],u),tsiz[u]+=tsiz[edge[u][e]];
}
inline void calc(){
ban[G]=true;
group[G]=G;
Linear_base::clear(f[G]);
Linear_base::insert(f[G],g[G]);
dfs_q(G,0);
for(int re e=0;e<edge[G].size();++e)
if(!ban[edge[G][e]])dfs(edge[G][e],G,edge[G][e]);
for(int re i=1;i<=tail;++i){
int re u=que[i];
for(int re q=last[u],v=to[q];q;v=to[q=nxt[q]]){
if(!have[q>>1]&&group[u]!=group[v]){
have[q>>1]=true;
Linear_base::merge(res,f[u],f[v]);
ans[q>>1]=Linear_base::query(res);
}
while(nxt[q]&&have[nxt[q]>>1])nxt[q]=nxt[nxt[q]];
}
}
}
inline void dfs_banall(int u){
ban[u]=true;
for(int re e=0;e<edge[u].size();++e)
if(!ban[edge[u][e]])dfs_banall(edge[u][e]);
}
signed main(){
n=getint();
q=getint();
for(int re i=1;i<=n;++i)g[i]=getint();
for(int re i=1;i<n;++i)addedge(getint(),getint());
for(int re i=1;i<=q;++i)addq(getint(),getint());
siz[1]=n;
for(int re i=1;i<=n;++i){
while(!ban[i]){
tail=0;
total=mx=siz[i];
G=i;
find_G(i,0);
if(tail==0)dfs_banall(G);
else calc();
}
}
for(int re i=1;i<=q;++i)outint(ans[i]),pc('\n');
FLUSH();
return 0;
}