hdu 6191 Query on A Tree(字典树+启发式合并)

题目链接

每个节点建一颗字典树,启发式合并就好了。

内存n*logn*logn,内存超限,考虑合并完之后废弃的字典树的节点存一下,后面再次利用。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
int tree[maxn*55][2],a[maxn];
vector<int>G[maxn],S[maxn],ask1[maxn],ask2[maxn];
int n,q,tol,root[maxn],ans[maxn];
int que[maxn*55],top;
void Insert(int c,int x)
{
    for(int i=30;i>=0;i--)
    {
        int t=(x>>i&1);
        if(tree[c][t]==0)
        {
            int cnt;
            if(top) cnt=que[top--];
            else cnt=++tol;
            tree[c][t]=cnt;
            tree[cnt][0]=tree[cnt][1]=0;
        }
        c=tree[c][t];
    }
}
int query(int c,int x)
{
    int ans=0;
    for(ll i=30;i>=0;i--)
    {
        int t=(x>>i&1);
        if(tree[c][t^1])
            ans|=(1<<i),c=tree[c][t^1];
        else
            c=tree[c][t];
    }
    return ans;
}
void del(int c)
{
    if(tree[c][0])
        del(tree[c][0]);
    if(tree[c][1])
        del(tree[c][1]);
    que[++top]=c;
    tree[c][0]=tree[c][1]=0;
}
void dfs(int v)
{
    Insert(root[v],a[v]);
    S[root[v]].push_back(a[v]);
    for(int i=G[v].size()-1;i>=0;i--)
    {
        int to=G[v][i];
        dfs(to);
        if(S[root[v]].size()>=S[root[to]].size())
        {
            for(int j=S[root[to]].size()-1;j>=0;j--)
            {
                Insert(root[v],S[root[to]][j]);
                S[root[v]].push_back(S[root[to]][j]);
            }
            del(root[to]);
        }
        else
        {
            for(int j=S[root[v]].size()-1;j>=0;j--)
            {
                Insert(root[to],S[root[v]][j]);
                S[root[to]].push_back(S[root[v]][j]);
            }
            del(root[v]);
            root[v]=root[to];
        }
    }
    for(int i=ask1[v].size()-1;i>=0;i--)
    {
        int t=ask2[v][i],x=root[v],y=ask1[v][i];
        ans[t]=query(x,y);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&q))
    {
        //memset(tree,0,sizeof(tree));
        for(int i=0;i<maxn;i++)
        {
            G[i].clear();
            S[i].clear();
            ask1[i].clear();
            ask2[i].clear();
        }
        top=tol=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            root[i]=++tol;
            tree[tol][0]=tree[tol][1]=0;
        }
        for(int i=2;i<=n;i++)
        {
            int x;scanf("%d",&x);
            G[x].push_back(i);
        }
        for(int i=1;i<=q;i++)
        {
            int v,x;scanf("%d%d",&v,&x);
            ask1[v].push_back(x);
            ask2[v].push_back(i);
        }
        dfs(1);
        for(int i=1;i<=q;i++)
            printf("%d\n",ans[i]);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值