Cs Round#56 D Find Path Union

题意:有一棵如下的完全二叉树,求所有给定结点到根节点的路径的并有多少条边。

一开始联想到线段树,发现结点的排布很像线段树的标号。于是模仿线段树敲了一下,交上去发现3个点MLE了。。。

无心优化,跑去看题解。题解的思路是自底向上,先将询问的结点排序,最后从最深的节点开始往上递推,记录每层开始分叉的结点,统计答案即可

正解:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
vector<LL>a;
queue<LL>q;
int n,ans=0;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        LL x;
        scanf("%lld",&x);
        a.push_back(x);
    }
    sort(a.begin(),a.end());
    while(a.size()||!q.empty()){
        LL maxn;
        if(!a.size())maxn=q.front();
        else if(q.empty())maxn=a.back();
        else maxn=max(q.front(),a.back());
        ans++;
        if(maxn>>1)q.push(maxn>>1);
        while(!q.empty()&&maxn==q.front())q.pop();
        while(a.size()&&maxn==a.back())a.pop_back();
    }
    printf("%d\n",ans-1);
    return 0;
}

76.92 points:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
map<uLL,bool>vis;
unsigned int n,ans=0;
uLL pw[62];
void form(){
    pw[0]=1;
    for(int i=1;i<=61;i++)pw[i]=1ll*pw[i-1]*2;
    for(int i=1;i<=61;i++)pw[i]--;
}
void query(uLL k,uLL l,uLL r,uLL x){
    //printf("%d\n",k);
    if(!vis[k]){
        ans++;
        vis[k]=1;
    }
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)query(k<<1,l,mid,x);
    else query(k<<1|1,mid+1,r,x);    
}
int main(){
    form();
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        uLL x;
        int t;
        scanf("%llu",&x);
        t=lower_bound(pw+1,pw+61,x)-pw;
        //printf("%d\n",t);
        query(1,1,1<<(t-1),x-pw[t-1]);
    }
    printf("%d\n",ans-1);
    return 0;
}

 

posted @ 2017-11-09 09:15  NINGLONG  阅读(131)  评论(0编辑  收藏  举报