[BZOJ5338][TJOI2018]xor

bzoj
luogu

descirption

现在有一棵以 \(1\) 为根节点的由 \(n\) 个节点组成的树,树上每个节点上都有一个权值 \(v_i\) 。现在有 \(Q\) 次操作,操作如下:
\(1\;x\;y\) :查询节点 \(x\) 的子树中与 \(y\) 异或结果的最大值
\(2\;x\;y\;z\) :查询路径 \(x\)\(y\) 上点与 \(z\) 异或结果最大值

sol

正在写线性基的同学们醒一醒
可持久化\(Trie\)树。
和可持久化线段树没什么区别。
自己\(yy\)了一种比较好写的方法,可以不记\(l\)\(r\),只计当前的\(dep\)也就是二进制位。
为什么会有人写主席树强行\(\log^2n\)啊。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e5+5;
struct node{int ch[2],sz;}t[N*35];
int n,m,v[N],val[N],mx,l,to[N<<1],nxt[N<<1],head[N],cnt;
int fa[N],dep[N],sz[N],son[N],top[N],dfn[N],rt[N],tot;
void link(int u,int v){
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void dfs1(int u,int f){
    fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    for (int e=head[u];e;e=nxt[e])
        if (to[e]!=f){
            dfs1(to[e],u),sz[u]+=sz[to[e]];
            if (sz[to[e]]>sz[son[u]]) son[u]=to[e];
        }
}
void dfs2(int u,int up){
    top[u]=up;dfn[u]=++cnt;
    if (son[u]) dfs2(son[u],up);
    for (int e=head[u];e;e=nxt[e])
        if (to[e]!=fa[u]&&to[e]!=son[u])
            dfs2(to[e],to[e]);
}
void modify(int &x,int p,int dep){
    t[++tot]=t[x];++t[x=tot].sz;
    if (!~dep) return;
    modify(t[x].ch[(p>>dep)&1],p,dep-1);
}
int query(int x,int y,int p,int dep){
    if (!~dep) return 0;
    int c=(p>>dep)&1;c^=1;
    if (t[t[x].ch[c]].sz-t[t[y].ch[c]].sz) return query(t[x].ch[c],t[y].ch[c],p,dep-1)|(1<<dep);
    c^=1;return query(t[x].ch[c],t[y].ch[c],p,dep-1);
}
int main(){
    n=gi();m=gi();
    for (int i=1;i<=n;++i) mx=max(mx,v[i]=gi());
    while ((1<<l)<mx) ++l;--l;
    for (int i=1;i<n;++i){
        int u=gi(),v=gi();
        link(u,v);link(v,u);
    }
    dfs1(1,0),cnt=0,dfs2(1,1);
    for (int i=1;i<=n;++i) val[dfn[i]]=v[i];
    for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],val[i],l);
    while (m--){
        int opt=gi();
        if (opt==1){
            int x=gi(),y=gi();
            printf("%d\n",query(rt[dfn[x]+sz[x]-1],rt[dfn[x]-1],y,l));
        }else{
            int x=gi(),y=gi(),z=gi(),ans=0;
            while (top[x]^top[y]){
                if (dep[top[x]]<dep[top[y]]) swap(x,y);
                ans=max(ans,query(rt[dfn[x]],rt[dfn[top[x]]-1],z,l));
                x=fa[top[x]];
            }
            if (dep[x]>dep[y]) swap(x,y);
            ans=max(ans,query(rt[dfn[y]],rt[dfn[x]-1],z,l));
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhoushuyu/p/9201039.html