[TJOI2018]异或

这大概是这个题最蒻的一篇题解了吧,供不会可持久化$Trie$且在解决本题之前不想学会的人食用

并不会可持久化$Trie$的蒟蒻本蒻遇到了这个题,然后用$Trie$维护的树链剖分水过去了

数集中的数与询问的异或最大值求解思路

思路很常见,比较好想,对数集中的所有数从高位到低位建立$01Trie$,然后贪心求解即可——设目前匹配到从高到低的第$i$位,若询问$x$的第$i$位为0,则优先进入到$Trie$树中当前节点的1方向,意义为在原最优解集上选择了所有第$i$位为1的数构成的子集作为新的最优解集,答案增加$2^{i-1}$,若当前节点的1方向不存在(原最优解集中不存在第$i$位为1的数)则进入0方向,答案不更新,询问$x$的第$i$位为1则相反,不再赘述。由进制的性质可得,贪心策略的正确性显然

考虑本题

子树问题常常通过$dfs$序解决,链上问题常常通过树链剖分解决,而树链剖分在其执行过程中维护了$dfs$序,故考虑通过树链剖分解决问题

树链剖分的查询按$dfs$序是区间连续的,故只需维护$Trie$上的每个节点对应的数集(以每个节点的$dfs$序为代表),对于每个查询在数集上进行二分,判断查询区间内$0/1$方向的节点的存在性即可

时间复杂度会比可持久化$Trie$多一个$log$,不过也是可过的

代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
struct edge{
    int next,to;
}e[maxn*2];
vector<int>vc[maxn*30];
int n,m,v[maxn],head[maxn],cnt,f[maxn],d[maxn],son[maxn];
int tr[maxn*30][2],size[maxn],top[maxn],id[maxn],rk[maxn];
void insert(int x,int id)
{
    for(int now=0,i=29;i>=0;i--)
    {
        int c=(x&(1<<i))?1:0;
        now=tr[now][c]?tr[now][c]:tr[now][c]=++cnt;
        vc[now].push_back(id);
    }
}
int query(int x,int y,int k)
{
    int ret=0;
    for(int now=0,i=29;i>=0;i--)
    {
        int to=(k&(1<<i))?0:1,trs=tr[now][to];
        if(upper_bound(vc[trs].begin(),vc[trs].end(),y)-lower_bound(vc[trs].begin(),vc[trs].end(),x))
            now=tr[now][to],ret+=(1<<i);
        else
            now=tr[now][to^1];
    }
    return ret;
}
void add(int x,int y)
{
    e[++cnt].next=head[x];
    e[cnt].to=y;
    head[x]=cnt;
}
void dfs1(int x)
{
    size[x]=1,d[x]=d[f[x]]+1;
    for(int v,i=head[x];i;i=e[i].next)
        if((v=e[i].to)!=f[x])
        {
            f[v]=x,dfs1(v),size[x]+=size[v];
            if(size[son[x]]<size[v])
                son[x]=v;
        }
}
void dfs2(int x,int tp)
{
    top[x]=tp,id[x]=++cnt,rk[cnt]=x;
    if(son[x])
        dfs2(son[x],tp);
    for(int v,i=head[x];i;i=e[i].next)
        if((v=e[i].to)!=f[x]&&v!=son[x])
            dfs2(v,v);
}
int sum(int x,int y,int k)
{
    int ret=0;
    while(top[x]!=top[y])
    {
        if(d[top[x]]<d[top[y]])
            swap(x,y);
        ret=max(ret,query(id[top[x]],id[x],k));
        x=f[top[x]];
    }
    if(id[x]>id[y])
        swap(x,y);
    return ret=max(ret,query(id[x],id[y],k));
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);
    for(int x,y,i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    cnt=0,dfs1(1),dfs2(1,1),cnt=0;
    for(int i=1;i<=n;i++)
        insert(v[rk[i]],i);
    for(int op,x,y,k,i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)
            printf("%d\n",query(id[x],id[x]+size[x]-1,y));
        else
        {
            scanf("%d",&k);
            printf("%d\n",sum(x,y,k));
        }
    }
    return 0;
}
posted @ 2021-02-10 00:28  Ivanovcraft  阅读(57)  评论(0编辑  收藏  举报