『FLA - III』Anxiety
完美二叉树
测试点 1
总共有
测试点 2 \sim 3
注意到
建树,对于每个询问暴力遍历整棵树并标记哪些节点和
时间复杂度
测试点 4 \sim 5
树上节点至多有
注意到
具体有多少呢?首先对于给定节点
可以得到满足条件的节点数量不超过
对于第
这里认为回答一次询问的时间复杂度为
这个做法能通过测试点 int 范围。
#include<bits/stdc++.h>
using namespace std;
int n,m,lim,w[300'000];
vector<int> v[300'000];
bool on[300'000];
long long ans;
void dfs(int x,int las,int step,int uim,function<void(int)> fun){
fun(x);
if(step<uim) for(int i:v[x]) if(i!=las) dfs(i,x,step+1,uim,fun);
}
long long query(int x,int y,int k){
ans=0ll;
dfs(x,0,0,k,[&](int x)->void{on[x]=1;});
dfs(y,0,0,k,[&](int x)->void{ans+=on[x]*w[x];});
dfs(x,0,0,k,[&](int x)->void{on[x]=0;});
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m,lim=(1<<n)-1;
for(int i=1;i<=lim;i++) cin>>w[i];
for(int i=2;i<=lim;i++) v[i].push_back(i/2),v[i/2].push_back(i);
for(int i=1;i<=m;i++){
static int x,y,k;
cin>>x>>y>>k;
cout<<query(x,y,k)<<'\n';
}
return 0;
}
测试点 6 \sim 7
现在尝试将问题转化,举个例子:询问和节点
这等价于询问所有和节点
为啥?因为节点
又因为节点
再来一个例子:询问和节点
这等价于询问所有和节点
现在尝试利用
又因为完美二叉树的性质很好,从任意节点向上枚举到根节点的时间复杂度为
时间复杂度
另外由于
测试点 8 \sim 10
沿用上一个做法,预处理节点
时间复杂度
#include<bits/stdc++.h>
using namespace std;
long long s[20][300'000];
int n,m,lim;
void dfs(int x){//预处理节点子树权值和
if(x*2>lim){
for(int i=1;i<=n;i++) s[i][x]=s[0][x];
return;
}
dfs(x*2),dfs(x*2+1);
for(int i=1;i<=n;i++) s[i][x]=s[0][x]+s[i-1][x*2]+s[i-1][x*2+1];
}
long long query(int x,int y,int k){
static int xi,yi,mid,cnt[2],a[2][40];
static long long ret;
xi=0,yi=1,cnt[0]=0,cnt[1]=0;
while(x!=y){
if(x<y) swap(x,y),swap(xi,yi);
a[xi][++cnt[xi]]=x,x/=2;
}
a[xi][++cnt[xi]]=x;
for(int i=cnt[yi];i>=1;i--) a[xi][++cnt[xi]]=a[yi][i];
k-=cnt[xi]/2;
if(k<0) return 0ll;
if(cnt[xi]%2==1){//存在唯一的路径中点
mid=a[xi][cnt[xi]/2+1];
ret=s[min(k,n)][mid];
}
else{//不存在路径中点需要处理的东西更多
mid=max(a[xi][cnt[xi]/2],a[xi][cnt[xi]/2+1]);
ret=s[min(k,n)][mid];
if(k>=1) ret+=s[min(k-1,n)][mid^1];
mid/=2,ret+=s[0][mid];
}
for(int i=1;i<=k&&mid!=0;i++){//向上枚举
if(k-i>=1) ret+=s[min(k-i-1,n)][mid^1];
mid/=2,ret+=s[0][mid];
}
return ret;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m,lim=(1<<n)-1;
for(int i=1;i<=lim;i++) cin>>s[0][i];
dfs(1);
for(int i=1;i<=m;i++){
static int x,y,k;
cin>>x>>y>>k;
cout<<query(x,y,k)<<'\n';
}
return 0;
}