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; }
Hello World