• BNUOJ 52318 Be Friends prim+Trie


    题目链接:

    https://acm.bnu.edu.cn/v3/problem_show.php?pid=52318

    B. Be Friends

    Case Time Limit: 2500ms
    Memory Limit: 524288KB

    题意

    给你n个点,每个点有一个权值a[i],对于两个点u,v,他们之间的边的权值为a[u]^a[v],现在让你求一颗最小生成树。

    题解

    Trie可以求离点u最近的点v(既u^v最小),利用这一点,我们用prim来求最小生成树, 可以用优先队列维护一下离我们已经扩展的集合的最近的点,最近的点是可以用Trie处理出来的。

    代码

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxnode=2e6+10;
    const int maxn=1e5+10;
    
    struct Node {
        int u,v;
        bool operator < (const Node& tmp) const {
            return (u^v)>(tmp.u^tmp.v);
        }
        Node(int u,int v):u(u),v(v) {}
    };
    
    ///ch[0]为超级节点,不止是代表第一个点,很多点会连到上面,所以它的cntv必须为0,代表着终结。
    struct Trie {
        int ch[maxnode][2];
    	//cntv统计子树下的单词节点个数,val记录单词节点
        int cntv[maxnode],val[maxnode];
        int sz,cnt;
        Trie() {
            sz=1;
            clr(ch[0],0);
            cnt=0;
        }
    
        void insert(int x) {
            cnt++;
            int arr[44]= {0},tot=0,tmp=x;
            while(tmp) {
                arr[++tot]=tmp&1;
                tmp>>=1;
            }
    
            int u=0;
            for(int i=33; i>=1; i--) {
                int c=arr[i];
                if(!ch[u][c]) {
                    clr(ch[sz],0);
                    cntv[sz]=0;
                    val[sz]=-10086;
                    ch[u][c]=sz++;
                }
                u=ch[u][c];
                cntv[u]++;
            }
            val[u]=x;
        }
    
        int query(int x) {
            if(cnt==0) return -1;
    
            int arr[44]= {0},tot=0,tmp=x;
            while(tmp) {
                arr[++tot]=tmp&1;
                tmp>>=1;
            }
    
            int u=0;
            for(int i=33; i>=1; i--) {
                int c=arr[i];
                if(cntv[ch[u][c]]) {
                    u=ch[u][c];
                } else {
                    u=ch[u][c^1];
                }
            }
            return val[u];
        }
    
        void del(int x) {
            cnt--;
            int arr[44]= {0},tot=0,tmp=x;
            while(tmp) {
                arr[++tot]=tmp&1;
                tmp>>=1;
            }
    
            int u=0;
            for(int i=33; i>=1; i--) {
                int c=arr[i];
                cntv[ch[u][c]]--;
                u=ch[u][c];
            }
        }
    
    } trie;
    
    int arr[maxn],n;
    map<int,bool> mp;
    
    int main() {
        scf("%d",&n);
        for(int i=1; i<=n; i++) scf("%d",&arr[i]);
        sort(arr+1,arr+n+1);
        n=unique(arr+1,arr+n+1)-arr-1;
    
        for(int i=2; i<=n; i++) {
            trie.insert(arr[i]);
        }
    
        priority_queue<Node> pq;
    
        if(n==1) {
            prf("0
    ");
            return 0;
        }
    
        ///prim求最小生成树
        int tmp=trie.query(arr[1]);
        pq.push(Node(arr[1],tmp));
        mp[arr[1]]=true;
    
        LL ans=0;
        for(int i=2; i<=n; i++) {
    
            while(mp[pq.top().v]){
                int u=pq.top().u;
                pq.pop();
                int v=trie.query(u);
                if(v>=0){
    //                prf("f(%d,%d)
    ",u,v);
                    pq.push(Node(u,v));
                }
            }
    
            int u=pq.top().u,v=pq.top().v;
            pq.pop();
            trie.del(v);
            mp[v]=true;
            ans+=u^v;
    
            int u2=trie.query(u);
            if(u2>=0){
                pq.push(Node(u,u2));
            }
    
            int v2=trie.query(v);
            if(v2>=0){
                pq.push(Node(v,v2));
            }
        }
    
        prf("%lld
    ",ans);
    
        return 0;
    }
  • 相关阅读:
    javascript 中加载图片大小与图片真是大小不一样解决方案
    连接数据库类
    jquery中“this”不同时刻的不同含义
    jquery中bind事件
    Sql中Output参数用法和分页存储过程
    C#中静态方法和静态变量的使用问题
    asp.net中javascript中json和C#对象之间的转换
    asp.net中加载自用户定义控件
    瀑布流布局——JS+绝对定位
    【笔记】——Javascript(1)
  • 原文地址:https://www.cnblogs.com/fenice/p/5944688.html
Copyright © 2020-2023  润新知