题解 P4592 【[TJOI2018]异或】
题意
给一棵
题解
不会数据结构的大彩笔居然不看题解 1A 了这题,感动……
首先这种题目应该是 01trie 求最大异或和。由于处理子树询问的时候对每个点都开一个 01trie 显然不现实,所以考虑可持久化 01trie。
首先考虑所有的子树内询问。因为可持久化 01trie 本质上是高度为
对于所有的链上询问,可以参考 Count on a tree 那题的做法,也就是一个节点上的可持久化 01trie 上有这个节点到根路径上所有数,对于查询的话直接树上差分就好了。因为这东西具有可减性所以没什么问题。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51;
struct Edge{
ll to,prev;
};
Edge ed[MAXN<<1];
ll n,qcnt,op,u,v,c,tot,totn,totd;
ll x[MAXN],last[MAXN],rt[MAXN],rt2[MAXN],dfn[MAXN],sz[MAXN];
ll fa[MAXN],depth[MAXN],rdfn[MAXN],hv[MAXN],top[MAXN],s[MAXN<<6];
ll ch[MAXN<<6][2];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void addEdge(ll from,ll to)
{
ed[++tot].prev=last[from];
ed[tot].to=to;
last[from]=tot;
}
inline ll insert(ll x,ll node,ll depth)
{
ll cur=++totn;
s[cur]=s[node]+1,ch[cur][0]=ch[node][0],ch[cur][1]=ch[node][1];
if(depth==-1)
{
return cur;
}
return ch[cur][(x>>depth)&1]=insert(x,ch[node][(x>>depth)&1],depth-1),cur;
}
inline void dfs(ll node,ll f)
{
ll mx=-1;
rdfn[dfn[node]=++totd]=node,sz[node]=1,depth[node]=depth[f]+1;
rt2[node]=insert(x[node],rt2[fa[node]=f],31);
for(register int i=last[node];i;i=ed[i].prev)
{
if(ed[i].to!=f)
{
dfs(ed[i].to,node),sz[node]+=sz[ed[i].to];
sz[ed[i].to]>mx?mx=sz[hv[node]=ed[i].to]:1;
}
}
}
inline void dfs2(ll node,ll link)
{
ll to;
top[node]=link;
if(!hv[node])
{
return;
}
dfs2(hv[node],link);
for(register int i=last[node];i;i=ed[i].prev)
{
(to=ed[i].to)!=fa[node]&&to!=hv[node]?dfs2(to,to):(void)1;
}
}
inline ll LCA(ll x,ll y)
{
while(top[x]!=top[y])
{
depth[top[x]]<depth[top[y]]?swap(x,y):(void)1,x=fa[top[x]];
}
return depth[x]<depth[y]?x:y;
}
inline ll query(ll x,ll lc,ll rc,ll depth)
{
if(depth==-1)
{
return 0;
}
ll nxt=!((x>>depth)&1),d=nxt^(!(s[ch[rc][nxt]]-s[ch[lc][nxt]]));
return (d<<depth)+query(x,ch[lc][d],ch[rc][d],depth-1);
}
inline ll query(ll x,ll l1,ll l2,ll l3,ll l4,ll depth)
{
if(depth==-1)
{
return 0;
}
ll nxt=!((x>>depth)&1);
ll d=nxt^(!(s[ch[l1][nxt]]+s[ch[l2][nxt]]-s[ch[l3][nxt]]-s[ch[l4][nxt]]));
return (d<<depth)+query(x,ch[l1][d],ch[l2][d],ch[l3][d],ch[l4][d],depth-1);
}
inline ll query(ll u,ll v,ll x)
{
ll l=LCA(u,v);
return query(x,rt2[u],rt2[v],rt2[l],rt2[fa[l]],31);
}
int main()
{
n=read(),qcnt=read();
for(register int i=1;i<=n;i++)
{
x[i]=read();
}
for(register int i=0;i<n-1;i++)
{
u=read(),v=read(),addEdge(u,v),addEdge(v,u);
}
dfs(1,0),dfs2(1,1);
for(register int i=1;i<=n;i++)
{
rt[i]=insert(x[rdfn[i]],rt[i-1],31);
}
for(register int i=1;i<=qcnt;i++)
{
op=read();
if(op==1)
{
u=read(),c=read();
printf("%d\n",query(c,rt[dfn[u]-1],rt[dfn[u]+sz[u]-1],31)^c);
}
if(op==2)
{
u=read(),v=read(),c=read(),printf("%d\n",query(u,v,c)^c);
}
}
}