[线性基 树链剖分 线段树 || ST表 || 点分治] BZOJ 4568 [Scoi2016]幸运数字

来源:互联网 发布:零基础自学编程 编辑:程序博客网 时间:2024/06/05 05:38

这个东西链剖之后就是个裸的区间线性基,是可以暴力合并的O(log2n)
所以暴力线段树是 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[N],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[N][KK];struct edge{  int u,v,next;}G[N<<1];int head[N],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].vint n;ll val[N];int size[N],fat[N];int depth[N];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[N],clk,top[N],back[N];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[N];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;}
原创粉丝点击