BZOJ4568 [Scoi2016]幸运数字 树上倍增+线性基

有一棵 N 个节点的树, Q 个询问,每次询问树上从 u v 的路径中能 x o r 出的最大值。 N 20000 , Q 200000 , 时限 6 s.
询问一个数集的 x o r 最大值显然线性基模板。
预处理树上每个点到它第 2 k 1 个父亲的线性基,合并时暴力将一个线性基插入另一个,每次合并的复杂度是 O ( log 2 A ) .查询时同样暴力合并即可。
需要用到线性基的插入,合并,求最大值操作。
最终得到了一个 O ( n log 3 n ) 的优秀算法(

#include<bits/stdc++.h> 
#define LL long long
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=20005;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Edge{
    int to,nex;
}e[N*2];
int n,q,head[N],tot,fa[N][16],dep[N];
LL a[N],fx[N][16][61],ans[61];
inline void ade(int u,int v)
{e[++tot]=(Edge){v,head[u]};head[u]=tot;}
void ins(LL *w,LL x)
{
    for(int i=60;i>=0;i--)
      if(x&(1LL<<i))
        {
            if(!w[i])
             {w[i]=x;break;}
            x^=w[i];
        }
}
LL qmax(LL *w)
{
    LL ret=0;
    for(int i=60;i>=0;i--)
      if((ret^w[i])>ret) ret^=w[i];
    return ret;
}
void Merge(LL *x,LL *y,LL *z)
{
    for(int i=60;i>=0;i--) x[i]=y[i];
    for(int i=60;i>=0;i--)
      if(z[i]) ins(x,z[i]);
}
void dfs(int u,int f)
{
    dep[u]=dep[f]+1; fa[u][0]=f;
    ins(fx[u][0],a[u]);
    for(int i=head[u];i;i=e[i].nex){
        int v=e[i].to; if(v==f) continue;
        dfs(v,u);
    }
}
inline int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=15;i>=0;i--)
      if(dep[fa[x][i]]>=dep[y])
        x=fa[x][i];
    if(x==y) return x;
    for(int i=15;i>=0;i--)
      if(fa[x][i]!=fa[y][i])
        x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
void solve(int x,int y)
{
    clr(ans,0);
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=15;i>=0;i--)
      if(dep[fa[x][i]]>=dep[y])
        Merge(ans,ans,fx[x][i]),x=fa[x][i];
    if(x==y) {ins(ans,a[x]);return;}
    for(int i=15;i>=0;i--)
      if(fa[x][i]!=fa[y][i])
        {
            Merge(ans,ans,fx[x][i]);
            Merge(ans,ans,fx[y][i]);
            x=fa[x][i]; y=fa[y][i];
        }
    ins(ans,a[x]); ins(ans,a[y]); ins(ans,a[fa[x][0]]);
//  Merge(ans,ans,fx[fa[x][0]][0]);
}
void solve2(int x,int y,int lca)
{
    clr(ans,0);
    for(;x!=lca;x=fa[x][0])
      ins(ans,a[x]);
    for(;y!=lca;y=fa[y][0])
      ins(ans,a[y]);
    ins(ans,a[lca]);
}
int main()
{
    n=read();q=read();
    for(int i=1;i<=n;i++) a[i]=read();
//  for(int i=1;i<=n;i++) ins(ans,a[i]);
//  Merge(ans,fx[0][0]);
//  cout<<qmax(ans)<<endl;
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        ade(u,v); ade(v,u);
    }
    dfs(1,0);
    for(int j=1;j<=15;j++)
      for(int i=1;i<=n;i++)
        {
            fa[i][j]=fa[fa[i][j-1]][j-1];
            Merge(fx[i][j],fx[i][j-1],fx[fa[i][j-1]][j-1]);
        }
//  cout<<qmax(fx[4][1])<<endl;
    while(q--)
    {
        int u=read(),v=read();
        solve(u,v);
        printf("%lld\n",qmax(ans));
//      solve2(u,v,lca);
//      cout<<qmax(ans)<<endl;
    }
    return 0;
}

好久没写博客了。。

猜你喜欢

转载自blog.csdn.net/wolf_reiser/article/details/80473247