zoukankan      html  css  js  c++  java
  • HDU5841 Alice and Bob (Trie+启发式合并)

    这题首先理解题意想暴力,在一个子树中,A想要两点异或值最大,B想要异或最小,A先选

    这其实就是告诉我们,A要选择一个点,使得他和其他点的异或值的最小值最大。

    对于异或贪心取值,一般来说,很容易想到使用01Trie上贪心。但是我们要求每个子树上的情况,暴力显然是平方级别。

    这个时候,我们遇到的问题是,统计树上信息且不带修改,因此想到可以用启发式合并,通过子树的信息来更新父节点的信息。

    对于更新来说,就是merge函数,merge函数也是递归到底部后回溯,按位维护,通过低位更新高位,具体方法可以看代码注释

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll,ll> pll;
    const int N=2e5+10;
    const int M=2e6+10;
    const int inf=0x3f3f3f3f;
    const int mod=772002;
    int h[N],ne[N],e[N],idx;
    int n,tr[M][2],rt[N];
    int w[N],times;
    int ans[N];
    int p[M],val[M];
    int sum[M];
    void add(int a,int b){
        e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    }
    int query(int u,int k,int dep){
        if(dep==-1)
            return val[u];
        int sign=(k>>dep)&1;
        if(tr[u][sign])
            return query(tr[u][sign],k,dep-1);
        else
            return query(tr[u][sign^1],k,dep-1);
    }
    void pushup(int u,int dep){
        int l=tr[u][0],r=tr[u][1];
        sum[u]=sum[l]+sum[r];
        if(sum[l]==1&&sum[r]==1){//只能取这两个点
            p[u]=p[l]^p[r];
        }
        else if(!sum[l]||!sum[r]){//只能取存在的一遍
            p[u]=sum[l]?p[l]:p[r];
        }
        else if(sum[l]>1&&sum[r]>1){//对于alice来说,取大的是优的
            p[u]=max(p[l],p[r]);
        }
        else{//取最小的值,才是答案
            if(sum[l]!=1)
                swap(l,r);
            p[u]=p[l]^query(r,p[l],dep-1);
        }
    }
    void insert(int &u,int dep,int k){
        int i;
        if(!u)
            u=++times;
        if(dep==-1){
            sum[u]=1;
            p[u]=val[u]=k;
            return ;
        }
        if(k>>dep&1)
        insert(tr[u][1],dep-1,k);
        else
        insert(tr[u][0],dep-1,k);
        pushup(u,dep);
    }
    int Merge(int u,int v,int dep){
        int i;
        if(!u||!v)
            return u|v;
        if(dep==-1){
            sum[u]+=sum[v];//最后一位更新数据
            if(sum[u]>1){
                p[u]=0;
            }
            else{
                p[u]=val[u];
            }
            return u;
        }
        tr[u][0]=Merge(tr[u][0],tr[v][0],dep-1);
        tr[u][1]=Merge(tr[u][1],tr[v][1],dep-1);
        pushup(u,dep);
        return u;
    }
    void dfs(int u,int fa){
        insert(rt[u],16,w[u]);
        int i;
        for(i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(j==fa)
                continue;
            dfs(j,u);
            rt[u]=Merge(rt[u],rt[j],16);
        }
        if(sum[rt[u]]>1)
            ans[u]=p[rt[u]];
    }
    void init(){
        int i;
        times=0,idx=0;
        memset(h,-1,sizeof h);
        memset(sum,0,sizeof sum);
        memset(ans,-1,sizeof ans);
        memset(rt,0,sizeof rt);
        memset(tr,0,sizeof tr);
    }
    int main(){
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        int cnt=1;
        while(t--){
            cin>>n;
            int i;
            init();
            for(i=1;i<=n;i++){
                cin>>w[i];
            }
            for(i=1;i<n;i++){
                int a,b;
                cin>>a>>b;
                add(a,b);
                add(b,a);
            }
            dfs(1,-1);
            int m;
            cin>>m;
            cout<<"Case #"<<cnt++<<":"<<endl;
            while(m--){
                int u;
                cin>>u;
                cout<<ans[u]<<endl;
            }
        }
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    Java设计模式之依赖倒置原则
    windows 下安装apache 遇到的问题
    Java序列化相关
    批量插入————优化
    接口相关
    Redis使用及工具类
    面试回顾——kafka
    面试回顾——List<T>排序
    Java面试——线程池
    面试回顾——session相关
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13602474.html
Copyright © 2011-2022 走看看