zoukankan      html  css  js  c++  java
  • HDU 4757 Tree(可持续化字典树,lca)

    题意:询问树上结点x到结点y路上上的权值异或z的最大值。

    任意结点权值 ≤ 2^16,可以想到用字典树。

    但是因为是询问某条路径上的字典树,将字典树可持续化,字典树上的结点保存在这条路径上的二进制数。

    按照dfs序建树,结点u的字典树表示u到根结点路径上的字典树。

    如果两个结点u和v,在同一条通往根结点的路径上,将会满足可减性。

    因此只需要知道u、v、lca和fa[lca]四个结点的字典树就可以回答了。

    /*********************************************************
    *            ------------------                          *
    *   author AbyssFish                                     *
    **********************************************************/
    #include<cstdio>
    #include<iostream>
    #include<string>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<stack>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<cmath>
    #include<numeric>
    #include<climits>
    using namespace std;
    
    const int maxn = 1e5+5;
    const int maxd = 16;
    const int maxnds = (maxd+1)*maxn;
    
    
    int hd[maxn], nx[maxn<<1], to[maxn<<1], ec;
    void add_edge(int u,int v)
    {
        nx[ec] = hd[u];
        to[ec] = v;
        hd[u] = ec++;
    }
    void init_g(int n){ memset(hd+1,0xff,n*sizeof(int)); ec = 0; }
    #define eachedge int i = hd[u]; ~i; i = nx[i]
    #define ifvalid int v = to[i]; if(v == fa[u]) continue;
    
    struct Node
    {
        int ch[2];
        int v;
    }p[maxnds];
    int tot;
    
    int n,m;
    int stk[maxd+5];
    
    inline int *dcmp(int x)
    {
        for(int i = 0; i < maxd; i++){
            stk[i] = x>>i&1;
        }
        return stk;
    }
    
    void build(int *o, int v)
    {
        int *s = dcmp(v);
        for(int i = maxd-1; i >= 0; i--){
            o = &(p[*o].ch[s[i]]);
            p[++tot] = p[*o];
            *o = tot;
            p[*o].v++;
        }
    }
    
    int a[maxn];
    int fa[maxn];
    int root[maxn];
    
    void dfs_build(int u,int f = 0)
    {
        p[root[u] = ++tot] = p[root[fa[u] = f]];
        build(root+u,a[u]);
        for(eachedge){
            ifvalid
            dfs_build(v,u);
        }
    
    }
    
    int *c_cmp;
    bool cmp_id(int i,int j){ return c_cmp[i] < c_cmp[j]; }
    
    int dep[maxn];
    int path[maxn<<1];
    int pid[maxn];
    int dfs_clk;
    
    
    void get_path(int u,int d)
    {
        dep[u] = d;
        path[++dfs_clk] = u;
        pid[u] = dfs_clk;
        for(eachedge){
            ifvalid
            get_path(v,d+1);
            path[++dfs_clk] = u;
        }
    }
    
    struct SparseTable
    {
        int mxk[maxn<<1];
        int d[maxn<<1][18];
        void init(int *mp,int *r, int n)
        {
            mxk[0] = -1;
            for(int i = 1; i <= n; i++){
                d[i][0] = r[i];
                mxk[i] = ((i&(i-1)) == 0) ?mxk[i-1]+1:mxk[i-1];
            }
            c_cmp = mp;
            for(int j = 1; j <= mxk[n]; j++){
                int t = (1<<j)-1, s = 1<<(j-1);
                for(int i = 1; i + t <= n; i++){
                    d[i][j] = min(d[i][j-1],d[i+s][j-1],cmp_id);
                }
            }
    
    
        }
        int RMQ(int l,int r)
        {
            int k = mxk[r-l];
            return min(d[l][k],d[r-(1<<k)][k],cmp_id);
        }
    }rmq;
    
    void lca_init(int u)
    {
        dfs_clk = 0;
        get_path(u,1);
        rmq.init(dep,path,dfs_clk);
    }
    
    int q_lca(int u, int v)
    {
        if(pid[u] > pid[v]) swap(u,v);
        return rmq.RMQ(pid[u],pid[v]+1);
    }
    
    vector<int> Tree;
    
    int cal_ch(int d)
    {
        int re = 0;
        for(int i = 0; i < (int)Tree.size(); i++){
            int o = Tree[i];
            re += o >= 0? p[p[o].ch[d]].v : -p[p[-o].ch[d]].v;
        }
        return re;
    }
    
    void dump(int d)
    {
        for(int i = 0; i < (int)Tree.size(); i++){
            int &o = Tree[i];
            o = o >= 0? p[o].ch[d] : -p[-o].ch[d];
        }
    }
    
    int query(int x,int y,int z)
    {
        int re = z&~((1<<16)-1);
        int *s = dcmp(z);
        Tree.clear();
        Tree.push_back(root[x]);
        Tree.push_back(root[y]);
        int lca = q_lca(x,y);
        Tree.push_back(-root[lca]);
        Tree.push_back(-root[fa[lca]]);
    
        int tmp = 0;
        for(int i = maxd-1; i >= 0; i--, tmp <<= 1){
            int d = s[i]^1;
            if(cal_ch(d)){
                tmp |= 1;
                dump(d);
            }
            else dump(d^1);
        }
        return re|(tmp>>1);
    }
    
    void solve()
    {
        for(int i = 1; i <= n; i++){
            scanf("%d",a+i);
        }
        init_g(n);
        for(int i = 1,u,v; i < n; i++){
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        tot = 0;
        dfs_build(1);
        lca_init(1);
        for(int i = 0, x, y, z; i < m; i++){
            scanf("%d%d%d",&x,&y,&z);
            printf("%d
    ",query(x,y,z));
        }
    }
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        //p[0] = {{0,0},0}; //root[0] = 0;
        while(~scanf("%d%d",&n,&m)){
            solve();
        }
        return 0;
    }
  • 相关阅读:
    学习笔记(5)——实验室集群LVS监控Web界面配置
    学习笔记(4)——实验室集群管理结点IP配置
    Java中List集合去除重复数据的方法
    Android App内部自动更新Library的使用(转载)
    AppBarLayout+TabLayout+RecyclerView+ViewPager+Fragment(布局悬浮)
    126、android html唤醒APP(转载)
    第三方免费加固横向对比(转载)
    124、@JavascriptInterface
    123、 android Retrofit 介绍和使用(转载)
    win10专业版激活步骤
  • 原文地址:https://www.cnblogs.com/jerryRey/p/5042024.html
Copyright © 2011-2022 走看看