• hdu4757 (可持久化字典树+LCA)


    题意

    给一棵树,每个节点有权值。每次询问要求回答一个值异或某条路径上的一个点的最大值。

    思路

    我们可以对每一个点开一个字典树,记录从这个点到根的路径上的所有数,然后求两点的LCA,然后把路径分成左端点到LCA的路和右端点到LCA的路来做。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxx = 1e5+10;
    struct node
    {
        int to,next;
    }e[maxx*2];
    int head[maxx],cnt;
    int depth[maxx],fa[maxx][22],lg[maxx];
    int trie[20*maxx][2],sum[20*maxx],val[20*maxx],tot;
    int rt[maxx];
    int a[maxx];
    void add(int u,int v)
    {
        e[++cnt].to=v;
        e[cnt].next=head[u];
        head[u]=cnt;
    }
    void update(int u,int v,int x)
    {
        rt[u]=++tot;
        int now=rt[u],pre=rt[v];
        for(int i=16;i>=0;i--)
        {
            int id=(x>>i)&1;
            trie[now][id]=++tot;
            trie[now][id^1]=trie[pre][id^1];
            now=trie[now][id];
            pre=trie[pre][id];
            sum[now]=sum[pre]+1;
        }
        val[now]=x;
    }
    int query(int l,int r,int x)
    {
        for(int i=16;i>=0;i--)
        {
            int id=(x>>i)&1;
            if(sum[trie[r][id^1]]>sum[trie[l][id^1]])
                r=trie[r][id^1],l=trie[l][id^1];
            else r=trie[r][id],l=trie[l][id];
        }
        return val[r]^x;
    }
    void dfs(int f,int fath)
    {
        update(f,fath,a[f]);
        depth[f]=depth[fath]+1;
        fa[f][0]=fath;
        for(int i=1;(1<<i)<=depth[f];i++)
            fa[f][i]=fa[fa[f][i-1]][i-1];
        for(int i=head[f];i;i=e[i].next)
            if(e[i].to!=fath)dfs(e[i].to,f);
    }
    int lca(int x,int y)
    {
        if(depth[x]<depth[y])swap(x,y);
        while(depth[x]>depth[y])
            x=fa[x][lg[depth[x]-depth[y]]-1];
        if(x==y)return x;
        for(int k=lg[depth[x]]-1;k>=0;k--)
            if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
        return fa[x][0];
    }
    void init()
    {
        memset(head,0,sizeof(head));
        tot=cnt=0;
        memset(depth,0,sizeof(depth));
        memset(fa,0,sizeof(fa));
        memset(trie,0,sizeof(trie));
        memset(sum,0,sizeof(sum));
        memset(lg,0,sizeof(lg));
        memset(rt,0,sizeof(rt));
        memset(val,0,sizeof(val));
    }
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            int u,v;
            for(int i=1;i<n;i++)
            {
                scanf("%d%d",&u,&v);
                add(u,v);add(v,u);
            }
            rt[0]=++tot;
            dfs(1,0);
            for(int i=1;i<=n;i++)
                lg[i]=lg[i-1]+(1<<lg[i-1]==i);
            int w;
            while(m--)
            {
                scanf("%d%d%d",&u,&v,&w);
                int la=lca(u,v);
                int ans=a[la]^w;
                if(la!=u)ans=max(query(rt[la],rt[u],w),ans);//避免空区间
                if(la!=v)ans=max(query(rt[la],rt[v],w),ans);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    1202实验三 进程调度实验
    1111实验二 作业调度模拟实验
    1009实验一 认识DOS
    一起了解操作系统发展史
    0909
    进程调度模拟程序
    试验三同学评论
    实验三 进程调度模拟程序
    作业调度模拟程序
    DOS命令解释程序的编写
  • 原文地址:https://www.cnblogs.com/HooYing/p/12459922.html
Copyright © 2020-2023  润新知