[线性基 树链剖分 线段树 || ST表 || 点分治] BZOJ 4568 [Scoi2016]幸运数字
2017-07-01 22:06
525 查看
这个东西链剖之后就是个裸的区间线性基,是可以暴力合并的O(log2n)
所以暴力线段树是 O(nlog4n)
改成ST表是 O(nlog3n)
而如果点分的话 应该是O(nlog2n)
所以暴力线段树是 O(nlog4n)
改成ST表是 O(nlog3n)
而如果点分的话 应该是O(nlog2n)
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define cl(x) memset(x,0,sizeof(x)) using namespace std; typedef long long ll; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(ll &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } const int N=20005; const int K=61; const int KK=17; ll tmp ,pnt; struct Base{ int base[K]; ll b[K]; Base(){ } Base(ll x){ *b=0; b[++*b]=x; for (int k=K-1;~k;k--) if (x>>k&1) { base[k]=1; break; } } void clear(){ cl(base); *b=0; } void Merge(ll *x,ll *y){ pnt=0; for (int i=1;i<=*x;i++) tmp[++pnt]=x[i]; for (int i=1;i<=*y;i++) tmp[++pnt]=y[i]; cl(base); *b=0; for (int i=1;i<=pnt;i++){ ll x=tmp[i]; for (int k=K-1;~k;k--) if (x>>k&1) if (!base[k]){ b[++*b]=x; base[k]=*b; //for (int j=1;j<*b;j++) // if (b[j]>>k&1) // b[j]^=x; break; }else x^=b[base[k]]; } } ll Query(){ ll x=0; for (int k=K-1;~k;k--) if (base[k] && (x^b[base[k]])>x) x^=b[base[k]]; return x; } }st [KK]; struct edge{ int u,v,next; }G[N<<1]; int head ,inum; inline void add(int u,int v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p; } #define V G[p].v int n; ll val ; int size ,fat ; int depth ; inline void dfs(int u,int fa){ size[u]=1; fat[u]=fa; depth[u]=depth[fa]+1; for (int p=head[u];p;p=G[p].next) if (V!=fa) dfs(V,u),size[u]+=size[V]; } int pre ,clk,top ,back ; inline void find(int u,int fa,int z){ pre[u]=++clk; top[u]=z; back[clk]=u; int maxv=0,son=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && size[V]>maxv) maxv=size[son=V]; if (son) find(son,u,z); for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son) find(V,u,V); } int Log ; inline void Build(){ for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1; for (int i=1;i<=n;i++) st[i][0]=Base(val[back[i]]); for (int k=1;k<KK;k++) for (int i=1;i<=n;i++) st[i][k].Merge(st[i][k-1].b,st[min(i+(1<<(k-1)),n+1)][k-1].b); } Base Ret; inline void merge(int l,int r){ int t=Log[r-l+1]; Ret.Merge(Ret.b,st[l][t].b); Ret.Merge(Ret.b,st[r-(1<<t)+1][t].b); } inline ll Query(int u,int v){ Ret.clear(); for (;top[u]!=top[v];u=fat[top[u]]){ if (depth[top[u]]<depth[top[v]]) swap(u,v); merge(pre[top[u]],pre[u]); } if (depth[u]>depth[v]) swap(u,v); merge(pre[u],pre[v]); return Ret.Query(); } int main(){ int x,y,Q; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(Q); for (int i=1;i<=n;i++) read(val[i]); for (int i=1;i<n;i++) read(x),read(y),add(x,y,++inum),add(y,x,++inum); dfs(1,0); find(1,0,1); Build(); while (Q--){ read(x); read(y); printf("%lld\n",Query(x,y)); } return 0; }
相关文章推荐
- BZOJ 4568 [Scoi2016]幸运数字 ——线性基 倍增
- bzoj 4568: [Scoi2016]幸运数字 (高斯消元求解线性基)
- BZOJ4568: [Scoi2016]幸运数字【线性基】
- [BZOJ]4568 [SCOI2016] 幸运数字 线性基合并
- [BZOJ]4568: [Scoi2016]幸运数字 倍增+线性基
- BZOJ 4568: [Scoi2016]幸运数字 [线性基 倍增]
- BZOJ 4568 [Scoi2016]幸运数字 【倍增线性基
- bzoj 4568: [Scoi2016]幸运数字 倍增维护线性基
- bzoj 4568 [Scoi2016]幸运数字 倍增+线性基
- bzoj 4568: [Scoi2016]幸运数字【树链剖分+线段树+线性基】
- bzoj 4568 [SCOI 2016] 幸运数字
- BZOJ 4568: [Scoi2016]幸运数字
- 【BZOJ 4568】[Scoi2016]幸运数字
- BZOJ4568 [Scoi2016]幸运数字 【点分治 + 线性基】
- 【BZOJ-4568】幸运数字 树链剖分 + 线性基合并
- BZOJ4568 [Scoi2016]幸运数字
- bzoj 4568: [Scoi2016]幸运数字
- BZOJ 4568: [Scoi2016]幸运数字
- BZOJ 4568 [Scoi2016]幸运数字
- bzoj 4568: [Scoi2016]幸运数字