本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:BZOJ4568
正解:线性基+链剖+线段树
解题报告:
考虑直接用线段树维护线性基,构出来之后,每次询问都只需要在树上跳就好了。
线性基可以暴力合并,合并的复杂度是$O(log^2n)$。
最后查询一遍合并得到的最终线性基就可以了。
$UPD$:
考虑树分治做法:我们把询问离线下来,然后每次分治的时候$dfs$求出重心到所有的点,路径上的线性基。
接着就看一下所有的询问,如果询问的两个点分居不同子树中,那么直接回答询问就好了,时间复杂度:$O(60*nlogn+q*60*60)$,而且线性基里面加$break$还有各种优化之后,远远不到上界…
当然如果强制在线的话,就可以用动态树分治的做法,保存下树的结构,存下重心到分治结构中每个点的线性基,回答就在分治结构树上走就好了。不过在线的这个做法空间复杂度是$O(60*nlogn)$的…
贴一发简单暴力无脑的解法一的代码:
//It is made by ljh2000 //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <ctime> #include <vector> #include <queue> #include <map> #include <set> #include <string> #include <complex> #include <bitset> using namespace std; typedef long long LL; typedef long double LB; typedef complex<double> C; const double pi = acos(-1); const int MAXN = 40011; const int MAXM = 400011; int n,m,ecnt,first[MAXN],to[MAXM],next[MAXM],top[MAXN],deep[MAXN],father[MAXN],size[MAXN],son[MAXN],id[MAXN],pre[MAXN],flag,ql,qr; LL val[MAXN],lin,ans; struct node{ LL s[62]; int dui[62],top; }a[MAXN*3],tmp; inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; } inline int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } inline LL getLL(){ LL w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } inline void dfs(int x,int fa){ size[x]=1; for(int i=first[x];i;i=next[i]) { int v=to[i]; if(v==fa) continue; deep[v]=deep[x]+1; father[v]=x; dfs(v,x); size[x]+=size[v]; if(size[v]>size[son[x]]) son[x]=v; } } inline void dfs2(int x,int fa){ id[x]=++ecnt; pre[ecnt]=x; if(son[x]) { top[son[x]]=top[x]; dfs2(son[x],x); } for(int i=first[x];i;i=next[i]) { int v=to[i]; if(v==fa || v==son[x]) continue; top[v]=v; dfs2(v,x); } } inline node merge(node q,node qq){ if(q.top>qq.top) swap(q,qq); for(int i=1;i<=q.top;i++) { lin=q.s[ q.dui[i] ]; for(int j=60;j>=0;j--) { if(!( (lin>>j) &1 )) continue; if(!qq.s[j]) { qq.dui[ ++qq.top ]=j/*!!!*/; qq.s[j]=lin; break; } lin^=qq.s[j]; } } return qq; } inline void build(int root,int l,int r){ if(l==r) { for(int i=60;i>=0;i--) if(val[pre[l]]>>i) { a[root].s[i]=val[pre[l]]; a[root].dui[1]=i; break; } a[root].top=1; return ; } int mid=(l+r)>>1; int lc=root<<1,rc=root<<1|1; build(lc,l,mid); build(rc,mid+1,r); a[root]=merge(a[lc],a[rc]); } inline void query(int root,int l,int r){ if(ql<=l && r<=qr) { if(!flag) tmp=a[root],flag=1; else tmp=merge(tmp,a[root]); return ; } int mid=(l+r)>>1; int lc=root<<1,rc=root<<1|1; if(ql<=mid) query(lc,l,mid); if(qr>mid) query(rc,mid+1,r); } inline void lca(int x,int y){ int f1=top[x],f2=top[y]; flag=0; while(f1!=f2) { if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y); ql=id[f1]; qr=id[x]; query(1,1,n); x=father[f1]; f1=top[x]; } if(deep[x]<deep[y]) swap(x,y); ql=id[y]; qr=id[x]; query(1,1,n); } inline void work(){ n=getint(); m=getint(); for(int i=1;i<=n;i++) val[i]=getLL(); int x,y; for(int i=1;i<n;i++) { x=getint(); y=getint(); link(x,y); link(y,x); } deep[1]=1; dfs(1,0); ecnt=0; top[1]=1; dfs2(1,0); build(1,1,n); while(m--) { x=getint(); y=getint(); lca(x,y); ans=0; for(int i=60;i>=0;i--) if(( ans^(tmp.s[i]) )>ans) ans^=tmp.s[i]; printf("%lld ",ans); } } int main() { #ifndef ONLINE_JUDGE freopen("4568.in","r",stdin); freopen("4568.out","w",stdout); #endif work(); return 0; } //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。