线性基+树链剖分(bzoj4568)

来源:互联网 发布:淘宝换货售后卡怎么写 编辑:程序博客网 时间:2024/04/25 18:59
#include <bits/stdc++.h>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|1Base 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<R)query(L,R,rs);}/* 如果不在一条链上,那么比较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]]<dep[top[y]]) swap(x,y);        query(tid[top[x]],tid[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;i<n;i++)    {        int 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;i<q;i++)    {        int aa=read(),bb=read();        printf("%lld\n",getmax(Change(aa,bb)));    }}
原创粉丝点击