zoukankan      html  css  js  c++  java
  • 2013杭州赛区Ants hdu4776

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4776

    参见大牛题解http://blog.csdn.net/dslovemz/article/details/15290899

    自己比赛的时候除了枚举每一位之外,就没什么想法了,看了大牛题解,思路才略为明朗。此题的关键还是在于K比较小,1 <= k <= 200000。

    先预处理一下树,求出根节点到每个节点的异或值,用此建出来一棵01字典树。

    求第k大之前,可以先想想如何去求第一大。把第一大求出来过后,就可以考虑如何放水,使得值变为第二大,再放水,得到第三大,以此下去。

    先求出对于每个数来说,最大的异或值是多少,O(n*18),顺便将经过的节点压栈,压栈是为了记录字典树上经过的路径,为了之后的回溯。回溯的过程就是求次大值的过程。

    对于n个数来说,用一个优先队列来保存所有数当前与其他数xor的最大值,此时队列首元素就是所有n个数中两个数xor的最大值。

    0.如果队列非空,每次将优先队列中的队首元素弹出,假设当前最大值是由u节点与v节点异或得到的。(u和v都是字典树上的两个叶子节点,表示两个数)。

    1.如果u==v,那么continue,进行下一轮循环。

    3.否则,当前队首元素中的最大值,即为第k大的数,此时k++。然后调整u能够得到的最大值,去求一个当前值的次大值,然后将次大值压入队列,继续0操作。

    先看的题解,按照自己的思路构造了一下程序结构,开始敲代码去:

    //start coding at 15:02
    //debug from 16:15
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <cmath>
    #include <iostream>
    
    using namespace std;
    
    #define ForEdge(i,u) for(int i=head[u];i!=-1;i=edge[i].next)
    #define For(i,forN) for(int i=0;i<(forN);i++)
    #define Rep(forN,i) for(int i=(forN);i>=0;i--)
    #define _clr(x,y)   memset(x,(y),sizeof(x))
    #define mp  make_pair
    #define sf  scanf
    #define pf  printf
    
    using namespace std;
    
    typedef __int64 LL;
    const int Maxn=110000,Maxl=61;
    struct Tire
    {
        int id[2*Maxn*Maxl+1][2],cnt[2*Maxn*Maxl+1],last[Maxn],curNode[Maxn],Ttot;
        int stk[Maxn][Maxl][2];
        void init(){id[Ttot=0][0]=id[0][1]=0;}
        int createNode()
        {
            Ttot++;     id[Ttot][0]=id[Ttot][1]=cnt[Ttot]=0;
            return Ttot;
        }
        void insert(LL tval)
        {
            LL curB=1ll<<60;
            int curId=0;
            For(i,Maxl)
            {
                int ind=(curB&tval)!=0;
                if(id[curId][ind]==0)   id[curId][ind]=createNode();
                curId=id[curId][ind];
                curB>>=1;
            }
            cnt[curId]++;
        }
        LL getMax(LL tval,int u)
        {
            LL curB=1ll<<60,ans=0;
            int curId=0;
            For(i,Maxl)
            {
                int ind=((curB&tval)==0);
                if(id[curId][ind]==0)   ind^=1;
                else ans|=curB;
                stk[u][i][0]=curId,stk[u][i][1]=ind;//将u所经过的路径压栈,第三维为0表示父节点,1表示是父节点的哪个孩子
                curB>>=1;
                curId=id[curId][ind];
            }
            if(ans==0 && cnt[curId]==1)     return -1;
            last[u]=(ans==0?2:1);   curNode[u]=curId;
            return ans;
        }
        LL getVal(LL tval,int u)
        {
            LL ans=0,curB=1ll<<60;
            For(i,Maxl)
            {
                int ind=(curB&tval)!=0;
                if(stk[u][i][1]^ind)   ans|=curB;
                curB>>=1;
            }
            return ans;
        }
        LL getNextMax(LL tval,int u)
        {
            if(last[u]<cnt[curNode[u]])   {last[u]++;return getVal(tval,u);}
            int curDeep=60,curId;
            LL curB=1;
            while(curDeep>=0)
            {
                int ind=(curB&tval)==0;
                curId=stk[u][curDeep][0];
                if(stk[u][curDeep][1]==ind && id[curId][ind^1]!=0)
                    break;
                else
                    curDeep--,curB<<=1;
            }
            if(curDeep<0)  return -1;
            stk[u][curDeep][1]^=1;      curId=id[curId][stk[u][curDeep][1]];
            curB>>=1,curDeep++;
            while(curDeep<Maxl)
            {
                int ind=(curB&tval)==0;
                if(id[curId][ind]==0)   ind^=1;
                stk[u][curDeep][0]=curId,stk[u][curDeep][1]=ind;
                curId=id[curId][ind],curB>>=1,curDeep++;
            }
            LL ans=getVal(tval,u);
            if(ans==0 && cnt[curId]==1)     return -1;
            last[u]=(ans==0?2:1);   curNode[u]=curId;
            if(ans==5 && u==3)
            {
                For(i,Maxl) cout<<stk[u][i][1]<<" ";cout<<endl;
            }
            return ans;
        }
    }tire;
    
    int head[Maxn],etot,n,K;
    struct Edge
    {
        int to,next;    LL  cost;
    }edge[Maxn*2];
    void init_edge()
    {
        etot=0;_clr(head,-1);
    }
    void add_edge(int u,int v,LL cost)
    {
        edge[etot].cost=cost;
        edge[etot].to=v;
        edge[etot].next=head[u];
        head[u]=etot++;
    }
    LL val[Maxn];
    bool vis[Maxn];
    
    void dfs(int u)
    {
        vis[u]=true;
        ForEdge(i,u)
        {
            int v=edge[i].to;
            if(!vis[v])
            {
                val[v]=val[u]^edge[i].cost;
                dfs(v);
            }
        }
    }
    
    LL Ans[Maxn*2];
    LL dAns[Maxn];
    void debug()
    {
        for(int i=1;i<=n;i++)   cout<<val[i]<<" ";cout<<endl;
        //for(int i=1;i<=n;i++)   cout<<tire.getMax(val[i],i)<<" ";cout<<endl;
        int tcnt=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        if(i==j)    continue;
        else dAns[tcnt++]=val[i]^val[j];
        sort(dAns,tcnt+dAns);
        sort(Ans+1,Ans+K+1);
        for(int i=0;i<tcnt;i++)cout<<dAns[i]<<" ";cout<<endl;
        for(int i=1;i<=K;i++)   cout<<Ans[i]<<" ";cout<<endl;
    }
    
    void solve()
    {
        _clr(vis,false);    val[1]=0;
        dfs(1);
        tire.init();
        for(int i=1;i<=n;i++)
        tire.insert(val[i]);
        priority_queue < pair < LL ,int > > q;
        for(int i=1;i<=n;i++)
        {
            LL tmp=tire.getMax(val[i],i);
            if(tmp>=0)
            q.push(mp(tmp,i));
        }
        K=0;
        while(!q.empty() && K<Maxn*2)
        {
            int u=q.top().second;
            LL tmp=q.top().first;   q.pop();
            if(tmp<0)  continue;
            Ans[++K]=tmp;
            tmp=tire.getNextMax(val[u],u);
            if(tmp!=-1)  q.push(mp(tmp,u));
        }
    }
    
    int main()
    {
        while(~sf("%d",&n) && n)
        {
            int u,v;    LL cost;
            init_edge();
            For(i,n-1)  sf("%d%d%I64d",&u,&v,&cost),add_edge(u,v,cost),add_edge(v,u,cost);
            solve();
            int m;
            sf("%d",&m);
            while(m--)
            {
                int k;
                sf("%d",&k);
                if(k<=0 || k>K) puts("-1");
                else
                pf("%I64d
    ",Ans[k]);
            }
        }
        return 0;
    }
  • 相关阅读:
    Jenkins插件管理及汉化
    rpm安装Jenkins报错
    Codeforces Round #572 (Div. 2) A.
    [kuangbin带你飞]专题一 简单搜索 A棋盘问题
    北京信息科技大学第十一届程序设计竞赛(重现赛)I
    北京信息科技大学第十一届程序设计竞赛(重现赛)H
    北京信息科技大学第十一届程序设计竞赛(重现赛)B
    nyoj 206-矩形的个数 (a*b*(a+1)*(b+1)/4)
    nyoj 241-字母统计 (python count)
    nyoj 242-计算球体积 (pi*r*r*r*4/3)
  • 原文地址:https://www.cnblogs.com/CooCoo/p/3417938.html
Copyright © 2011-2022 走看看