线性基+树链剖分(bzoj4568)

#include 
using namespace std;
typedef  long long  ll;
const int N=20005;
const int m_base=60;
ll read()
{
    long long 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 Base
{
    ll a[m_base+1];
    Base()
    {
        memset(a,0,sizeof(a));
    }
};
void add(Base &y,ll x)/*生成一组线性基*/
{
    for(int i=m_base;~i;i--)
    {
        if((x>>i)&1)
        {
            if(y.a[i])
                x^=y.a[i];
            else
            {
                y.a[i]=x;
                break;
            }
        }
    }
}
int siz[N],top[N],son[N],dep[N],tid[N],rk[N],fa[N];
//siz[]数组,用来保存以x为根的子树节点个数
//top[]数组,用来保存当前节点的所在链的顶端节点
//son[]数组,用来保存重儿子
//dep[]数组,用来保存当前节点的深度
//fa[]数组,用来保存当前节点的父亲
//tid[]数组,用来保存树中每个节点剖分后的新编号
//rk[]数组,线段树中编号对应的原节点编号
int cnt,tim;
ll ac[N];
struct node
{
    int next,to;
} edge[N*2];
int head[N];
void intt()
{
    cnt=tim=0;
    memset(son,-1,sizeof(son));
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
void dfs1(int u,int pre/*fa*/,int de)
{/*求出每个点的深度和父节点,和重儿子*/
    dep[u]=de;fa[u]=pre;siz[u]=1;
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=pre)
        {
            dfs1(v,u,de+1);
            siz[u]+=siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])
                son[u]=v;
        }
    }
}
void dfs2(int u,int tp)
{/*给链编号,形成一一对应的关系*/
    top[u]=tp;
    tid[u]=++tim;
    rk[tid[u]]=u;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=son[u]/*不是u的重儿子*/&&v!=fa[u]/*不是u的父节点*/)
            dfs2(v,v);
    }
}
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
Base sum[4*N],ans;
void up(int rt)
{
    //    sum[rt]=sum[rt<<1];
    //    for(int i=0;i<=m_base;i++)
    //      if(sum[rt<<1|1].a[i])
    //        sum[rt].add(sum[rt<<1|1].a[i]);
    for(int i=m_base;i>=0;i--) sum[rt].a[i]=sum[rt<<1].a[i];
    for(int i=m_base;i>=0;i--)
        if(sum[rt<<1|1].a[i])
            add(sum[rt],sum[rt<<1|1].a[i]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=Base();
        add(sum[rt],ac[rk[l]]);
        return;
    }
    int mid=(l+r)>>1;
    build(ls);
    build(rs);
    up(rt);
}
void query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        for(int i=0;i<=m_base;i++)
            if(sum[rt].a[i])
                add(ans,sum[rt].a[i]);
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=L)query(L,R,ls);
    if(mid/*
 如果不在一条链上,那么比较x,y点链顶的父节点深度,更新深度深的链(进行交换,把深度深的赋予为x),更新完后,将范围调整到y--fa[top[x]],然后一直迭代,直到在同一个链上。
 */
int n,q;
Base Change(int x,int y)
{
    ans=Base();
    while(top[x]!=top[y])
    {
        if(dep[top[x]]1,n,1);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    query(tid[x],tid[y],1,n,1);
    return ans;
}
ll getmax(Base x)
{
    ll tt=0;
    for(int i=m_base;~i;i--)
        if(((tt>>i)&1)==0&&x.a[i])
            tt^=x.a[i];
    return tt;
}
int main()
{
    n=read(),q=read();
    intt();
    for(int i=1;i<=n;i++)
        ac[i]=read();
    for(int i=1;iint x=read(),y=read();
        addedge(x,y);
        addedge(y,x);
    }
    dfs1(1,0,0);
    dfs2(1,1);
    build(1,n,1);
    for(int i=0;iint aa=read(),bb=read();
        printf("%lld\n",getmax(Change(aa,bb)));
    }
}

你可能感兴趣的:(线性基,树链剖分)