[bzoj4568][Scoi2016]幸运数字

来自FallDream的博客,未经允许,请勿转载,谢谢。


A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5 和 11 ,可以保留的幸运值为 14 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。
n<=20000 Q<=200000
 
如果用树剖维护线性基的话有4个log,所以考虑倍增,维护每个点向上2^k个点的线性基,然后询问的时候合并4个线性基即可。
复杂度nlog^3 + Qlog^2
貌似有个点分治做法,每次处理过跟的询问 只有两个log
#include<iostream>
#include<cstdio>
#define MD 14
#define MN 20000
#define ll long long
#define ML 60
using namespace std;
inline int read()
{
    int 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 data{ll s[ML+1];
    void Add(ll x)
    {
        for(int i=ML;~i;--i)
            if(x&(1LL<<i))
            {
                if(s[i]) x^=s[i];
                else {s[i]=x;break;}
            }
    }
    friend data operator + (data a,data b)
    {
        data c=a;
        for(int i=ML;~i;--i)
            if(b.s[i]) c.Add(b.s[i]);
        return c;
    }
}f[MD+1][MN+5];ll a[MN+5];
int n,Q,fa[MD+1][MN+5],head[MN+5],cnt=0,Log[MN+5],dep[MN+5];
struct edge{int to,next;}e[MN*2+5]; 
inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;    
}

void Dfs(int x,int fat)
{
    fa[0][x]=fat;f[0][x].Add(a[x]);
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=fat)
        {
            dep[e[i].to]=dep[x]+1;
            Dfs(e[i].to,x);    
        }
}

inline int Up(int x,int k)
{
    for(int j=0;k;k>>=1,++j)
        if(k&1) x=fa[j][x];
    return x; 
}

inline int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    x=Up(x,dep[x]-dep[y]);
    if(x==y) return x;
    for(int i=MD;~i;--i)
        if(fa[i][x]!=fa[i][y])
            x=fa[i][x],y=fa[i][y];
    return fa[0][x];
}

data Solve(int x,int y)
{
    int len=Log[dep[x]-dep[y]+1];
    return f[len][x]+f[len][Up(x,dep[x]-dep[y]+1-(1<<len))];
}

int main()
{
    n=read();Q=read();Log[0]=-1;
    for(int i=1;i<=n;++i) scanf("%lld",&a[i]),Log[i]=Log[i>>1]+1;
    for(int i=1;i<n;++i) ins(read(),read());
    Dfs(dep[1]=1,0);
    for(int i=1;i<=MD;++i)
        for(int j=1;j<=n;++j)
        {
            fa[i][j]=fa[i-1][fa[i-1][j]];
            if(dep[j]-(1<<i)>=0) f[i][j]=f[i-1][j]+f[i-1][fa[i-1][j]];    
        }
    for(int i=1;i<=Q;++i)
    {
        int x=read(),y=read(),z=lca(x,y);
        data ans=Solve(x,z)+Solve(y,z);
        ll res=0;
        for(int i=ML;~i;--i) res=max(res,res^ans.s[i]);
        printf("%lld
",res);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/bzoj4568.html