• [TJOI2018] Xor 异或 (可持久化Trie,树链剖分)


    题目描述

    现在有一颗以 1 为根节点的由 n 个节点组成的树,树上每个节点上都有一个权值 (v_i)。现在有 Q 次操作,操作如下:

    • 1 x y :查询节点 x 的子树中与 y 异或结果的最大值。
    • 2 x y z :查询路径 x到 y 上点与 z 异或结果最大值

    输入格式

    第一行是两个数字 n , Q 。
    第二行是 n 个数字用空格隔开,第 i 个数字 (v_i) 表示点 i 上的权值。
    接下来 n−1 行,每行两个数, x,y ,表示节点 x 与 y 之间有边。
    接下来 Q 行,每一行为一个查询,格式如上所述。

    输出格式

    对于每一个查询,输出一行,表示满足条件的最大值。

    样例

    样例输入

    7 5
    1 3 5 7 9 2 4
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    1 3 5
    2 4 6 3
    1 5 5
    2 5 7 2
    1 1 9
    

    样例输出

    7
    6
    12
    11
    14
    

    #### 数据范围与提示

    对于 10% 的数据,有 1≤n,Q≤100 。
    对于 20% 的数据,有 1≤n,Q≤1000。
    对于 40% 的数据,有 1≤n,Q≤10000。
    对于 100% 的数据,有 1≤n,Q≤100000。
    查询 1 中的 y≤ (2^{30}),查询中的 z≤ (2^{30})

    Solution

    这道题,就是一道可持久化Trie树
    关于可持久化Trie树,其实也很简单,有以下前置技能:

    • 主席树
    • 01 (Trie)

    1.储存
    使用主席树的储存结构来储存01 (Trie) 树。
    建立 (n) 个虚点作为根,然后记录每个点的左儿子右儿子以及计数。

    2.查询
    关于查询,其实和带修改的 (Trie) 树 差不多,当且仅当已经构建的新树中该节点的 (num) 值大于0,我们才可以继续下去查询.最后输出最大值即可。

    然后最后面套个剖分即可。

    代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=200008;
    ll c[maxn],cc[maxn];
    int son[maxn],n,q;
    int top[maxn],siz[maxn];
    int dep[maxn],fa[maxn];
    
    struct sj{
        int to;
        int next;
    }a[maxn];
    int size,head[maxn];
    
    void add(int x,int y)
    {
        a[++size].to=y;
        a[size].next=head[x];
        head[x]=size;
    }
    
    ll ch[maxn*40][2];
    ll tot,T[maxn];
    ll num[maxn*40];
    
    int insert(int pre,ll x,int v)
    {
        int u=++tot;
        ll c=((x>>v)&1);
        ch[u][0]=ch[pre][0];
        ch[u][1]=ch[pre][1];
        num[u]=num[pre]+1;
        if(v>=0)
        ch[u][c]=insert(ch[pre][c],x,v-1);
        return u;
    }
    
    ll ans,now[2];
    int query(int l,int r,ll x,int v)
    {
        ll c=((x>>v)&1);
        now[0]=num[ch[r][0]]-num[ch[l][0]];
        now[1]=num[ch[r][1]]-num[ch[l][1]];
        if(now[c^1])
        {
            ans+=(1<<v);
            if(v>=0)
            query(ch[l][c^1],ch[r][c^1],x,v-1);
        }
        else
        if(v>=0)
        query(ch[l][c],ch[r][c],x,v-1);
    }
    
    void dfs(int x)
    {
        siz[x]=1;
        for(int i=head[x];i;i=a[i].next)
        {
            int tt=a[i].to;
            if(!siz[tt])
            {
                dep[tt]=dep[x]+1;
                fa[tt]=x;
                dfs(tt);
                siz[x]+=siz[tt];
                if(siz[tt]>siz[son[x]])
                son[x]=tt;
            }
        }
    }
    
    int id[maxn],dum;
    void dfs1(int x,int y)
    {
        top[x]=y;
        id[x]=++dum;
        c[dum]=cc[x];
        if(son[x])
        dfs1(son[x],y);
        for(int i=head[x];i;i=a[i].next)
        {
            int tt=a[i].to;
            if(!top[tt])
            if(tt!=son[x])
                dfs1(tt,tt);
        }
    }
    
    int check(int x,int y,int w)
    {
        ll rest=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])
            swap(x,y);
            ans=0;
            query(T[id[top[x]]-1],T[id[x]],w,32);
            rest=max(ans,rest);
            x=fa[top[x]];
        }
        if(id[x]>id[y])
        swap(x,y);
        ans=0;
        query(T[id[x]-1],T[id[y]],w,32);
        rest=max(rest,ans);
        return rest;
    }
    
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)
        scanf("%lld",&cc[i]);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs(1); dfs1(1,1);
        for(int i=1;i<=n;i++)
        T[i]=insert(T[i-1],c[i],32);
        while(q--)
        {
            int opt,x,y,z;
            scanf("%d",&opt);
            if(opt==1)
            {
                scanf("%d%d",&x,&y);
                ans=0;
                query(T[id[x]-1],T[id[x]+siz[x]-1],y,32);
                cout<<ans<<endl;
            }
            else
            {
                scanf("%d%d%d",&x,&y,&z);
                if(x!=y)
                cout<<check(x,y,z)<<endl;
                else
                cout<<(cc[x]^z)<<endl;
            }
        }
    }
    
    
  • 相关阅读:
    C#学习
    1.计算机的硬件
    C++ bitset——高端压位卡常题必备STL
    Aragorn's Story
    Sql Server DTS使用
    Django的SQL注意事项(以及时间戳转换日期格式)
    HTML中复选框的使用方法
    Http常见状态码
    scrapy yield 回调函数不执行解决方案
    jsonp跨域请求
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9310324.html
Copyright © 2020-2023  润新知