1. 程式人生 > >Cs Round#56 D Find Path Union

Cs Round#56 D Find Path Union

ges turn empty ont tor orm int end query

題意:有一棵如下的完全二叉樹,求所有給定結點到根節點的路徑的並有多少條邊。

技術分享

一開始聯想到線段樹,發現結點的排布很像線段樹的標號。於是模仿線段樹敲了一下,交上去發現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; }

Cs Round#56 D Find Path Union