您的位置:首页 > 文旅 > 美景 > 上海市人民政府网站官网_网络维护人员是做什么的_襄阳seo推广_seo优

上海市人民政府网站官网_网络维护人员是做什么的_襄阳seo推广_seo优

2024/12/22 22:39:11 来源:https://blog.csdn.net/2302_79431881/article/details/144223886  浏览:    关键词:上海市人民政府网站官网_网络维护人员是做什么的_襄阳seo推广_seo优
上海市人民政府网站官网_网络维护人员是做什么的_襄阳seo推广_seo优

题目链接:P4715 【深基16.例1】淘汰赛 - 洛谷 | 计算机科学教育新生态

题目难度普及

  刷题心得:本题是我二刷,之前第一次刷是在洛谷线性表那个题单,当时印象深刻第  一篇题解是用的树来做,当时我不屑一顾(觉得花里胡哨),现在我开始刷树的题目着字分析,第一次学习到线性树的用法现在把他总结下

 

线段树

线段树是一种二叉树,也就是对于一个线段,我们会用一个二叉树来表示。比如说一个长度为4的线段,我们可以表示成这样:

这是什么意思呢? 如果你要表示线段的和,那么最上面的根节点的权值表示的是这个线段 1 ∼ 6 的和。根的两个儿子分别表示这个线段中 1 ∼ 3 和4 ~6的和,以此类推。

然后我们还可以的到一个性质:节点 i的权值 == 它的左儿子权值 +它的右儿子权值。

我们知道,一颗从 1 11 开始编号的二叉树,结点 i的左儿子和右儿子编号分别是i x 2 和 i x 2 + 1

建树代码

void build(int node,int start,int end){   //建树函数,参数是根节点和左右区间 if(start==end){		//如果两边相等 tree[node]=arr[start]; //填的就是数组里的初始值 return;  //递归边界 }int leftnode=node*2;  //算出左右节点(完全二叉树的性质) int rightnode=node*2+1;  int mid=(start+end)/2;    //把数组从中间劈成两半build(leftnode,start,mid);  //左边右边分开建树 build(rightnode,mid+1,end);tree[node]=tree[leftnode]+tree[rightnode]; //根节点的值=左根+右根 
}

查询和求区间和:

void update(int node,int start,int end,int id,int val){      //修改操作,参数分别是建树函数的那三个和修改节点的编号和修改的值if(start==end){ //递归边界,如果是叶节点tree[node]+=val; //修改node节点的值return;}int leftnode=node*2;  //算出左右子树和中点int rightnode=node*2+1;  int mid=(start+end)/2;   if(id>=start&&id<=mid) //如果要改的地方在中点左边update(leftnode,start,mid,id,val);//那就递归修改左子树else update(rightnode,mid+1,end,id,val);//要么就递归修改右子树	tree[node]=tree[leftnode]+tree[rightnode]; //根节点更新 
} 
int query(int node,int start ,int end,int l,int r){ //查询函数,l和r是求和的左右区间if(l<=start&&r>=end)  //如果求和的区间已经当前的部分包含了
//(比如当前在[1,3]区间,让你求[1,5],那你就要求[1,3]+[4,5],直接把建树的时候算好的[1,3]的和加上去就行了)return tree[node]; //直接返回根节点int leftnode=node*2;  //又双叒叕是左右子树和中点int rightnode=node*2+1;  int mid=(start+end)/2;int sum=0; //就是要返回的和啊   if(l<=mid) //如果要求和的区间包含中点左边的部分sum+=query(leftnode,start,mid,l,r); //那就加上左边那块if(r>mid) //同理,如果右边还有那就加上右边那块sum+=query(rightnode,mid+1,end,l,r);return sum; //返回sum,不解释
}

线段树好处:所以介绍了这么多线段树,线段树到底有什么用前缀和不是也可以求和吗,可是如果修改一个值再求和前缀和,每一个前缀和都要修改时间复杂度就是o(n)了,线段树它可以把时间复杂度降低降低再降低,把修改和查询的时间复杂度都降到O(log⁡n)。

最后奉上本题代码:

#include<bits/stdc++.h>  // 万能头文件
using namespace std;
typedef long long ll;
//const int N = 100010;      
int n;struct node{int power;//能力值 int id;//国家序号 
}a[150],tree[600]; //a用来存储数据,tree是存线段树的数组 node maxn(node a,node b){  //返回两个结构体里能力值更大的那个return a.power>b.power?a:b;
}
node minn(node a,node b)
{return a.power < b.power ? a : b;//返回两个结构体里能力值更小的那个
}
void build(int node,int start,int end)//建树函数,参数是根节点和左右节点 
{if(start == end)//两边相等 {tree[node] = a[start];//填的就是数组的初始值 ,即叶子节点不需要划分 return;//边界 }int leftNode = node * 2;//算出左右节点(完全二叉树的性质) int rightNode = node * 2 + 1;int mid = (start + end) / 2;//把数组从中间分开 build(leftNode,start,mid);build(rightNode,mid + 1,end);tree[node]=  maxn(tree[leftNode],tree[rightNode]);  //父节点是左右子节点里更大的;
}
int main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);cin >> n;for(int i=1; i<= (1<<n); i++){cin >> a[i].power;a[i].id = i;}build(1,1,(1<<n));cout<<minn(tree[2],tree[3]).id;return 0;  
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com