线段树模板
来源:互联网 发布:电脑桌面提示语软件 编辑:程序博客网 时间:2024/06/06 07:31
原贴:http://blog.csdn.net/aleichen/article/details/52068437
//===========================================
//segment tree//final version
//by kevin_samuel(fenice)
//本模板为转载模板,后面的注释和主函数的验证为Alei添加
#include <iostream>
#include <cstdio>
#include <cmath>
//线段树
using namespace std;
#define MAXN 100
#define INF 0x3fffffff
int A[MAXN]; //操作的序列,记得为(1...n)非(0...n)
//int max;
//int min;
struct node
{
int left;
int right;
int max; //维护最大值
int sum; //维护区间和
int min; //维护最小值
}Tree[MAXN<<2]; //存储线段树
void maintain(int root) //向上调整,使得让线段树维护区间最小值最大值区间和
{
int LC = root<<1; //此根的左孩子
int RC = (root<<1)+1; //此根的右孩子
Tree[root].sum = Tree[LC].sum + Tree[RC].sum; //根的区间和
Tree[root].max = max(Tree[LC].max,Tree[RC].max); //根的最大值
Tree[root].min = min(Tree[LC].min,Tree[RC].min); //根的最小值
}
void Build(int root,int start,int end) //构建线段树
{ //初始化时传入Build(1,1,n);
Tree[root].left = start; //建区间大小
Tree[root].right = end;
if(start == end) //当到达叶子节点时
{
Tree[root].sum = A[start];
Tree[root].max = A[start];
Tree[root].min = A[start];
return;
}
int mid = (start + end)>>1; //中间分开
Build(root<<1,start,mid); //对左孩子建树,左边孩子的编号为root*2
Build((root<<1)+1,mid+1,end); //对右边孩子建树
maintain(root);
}
void update(int root,int pos,int value) //更新点的值
{
if(Tree[root].left == Tree[root].right && Tree[root].left == pos) //更新叶子节点的值
{
Tree[root].sum += value;
Tree[root].max += value;
Tree[root].min += value;
return;
}
int mid = (Tree[root].left + Tree[root].right)>>1; //中间分开成两个区间
if(pos <= mid) //更新的值在左孩子
update(root<<1,pos,value); //更新左孩子
else
update((root<<1)+1,pos,value); //更新的值在右孩子
maintain(root); //叶子节点更新完成后,会回溯到他的父节点,这样一直往上更新到根节点,维护线段树性质
}
int Query(int root,int start,int end) //查询区间和(start, end)根节点为1
{
if(start == Tree[root].left && Tree[root].right == end) //正好匹配到查询区间,直接返回区间和
{
return Tree[root].sum;
}
int mid = (Tree[root].left + Tree[root].right)>>1; //分开区间
int ret = 0;
if(end <= mid) //查询结果在左边区间
ret += Query(root<<1,start,end); //将左区间的查询结果返回,并记录在结果和中
else if(start >= mid+1) //查询结果在右区间
ret += Query((root<<1)+1,start,end);
else //查询结果包含在左右两个区间中
{
ret += Query(root<<1,start,mid); //查左的一部分
ret += Query((root<<1)+1,mid+1,end); //查右的一部分
}
return ret; //返回本次查询结果
}
/*********************************************************************/
LL RminQ(LL root, LL start, LL end) {
//查询区间和当前节点区间没有交集
if(start > Tree[root].right || end < Tree[root].left) return INF;
//当前节点区间包含在查询区间内
if(start <= Tree[root].left && Tree[root].right <= end) {
return Tree[root].min;
}
//分别从左右子树查询,返回两者查询结果的较小值
return min(RminQ(root<<1, start, end), RminQ((root<<1)+1, start, end));
}
/***********************************************************************/
int RminQ(int root,int start,int end) //查询区间最小值{
if(start == Tree[root].left && Tree[root].right == end) //正好匹配区间
{
return Tree[root].min;
}
int mid = (Tree[root].left + Tree[root].right)>>1; //区间分开,去查左右孩子
int ret = INF; //先把结果记录为很大
if(end <= mid) // 完全左区间匹配
ret = min(ret,RminQ(root<<1,start,end));
else if(start >= mid+1) //完全右区间匹配
ret = min(ret,RminQ((root<<1)+1,start,end));
else
{
int a = RminQ(root<<1,start,mid);
int b = RminQ((root<<1)+1,mid+1,end);
ret = min(a,b); //求左右区间和匹配区间相符的最小值的较小值
}
return ret; //记得要返回本次查询的结果
}
int RmaxQ(int root,int start,int end) //查询区间最大值
{
if(start == Tree[root].left && Tree[root].right == end)
{
return Tree[root].max;
}
int mid = (Tree[root].left + Tree[root].right)>>1;
int ret = 0; //************可能是 (-INF)要尽可能的小
if(end <= mid)
ret = max(ret,RmaxQ(root<<1,start,end)); //完全左孩子区间匹配
else if(start >= mid+1)
ret = max(ret,RmaxQ((root<<1)+1,start,end)); //完全右孩子区间匹配
else
{
int a = RmaxQ(root<<1,start,mid);
int b = RmaxQ((root<<1)+1,mid+1,end);
ret = max(a,b); //求的左右两个区间和匹配区间相符的最大值得较大者
}
return ret; //记得返回结果
}
int main()
{
for(int i = 1; i <= 10; i++)
A[i] = i;
Build(1,1,10);
cout << " (1..10)的数组,对应值如下:" << endl;
for(int i = 1; i <= 10; i++)
cout << A[i] << " ";
cout << endl;
cout << "(1..5)区间最小值:" << RminQ(1,1,5) << endl;
cout << " (1..5)区间最大值:" << RmaxQ(1,1,5) << endl;
cout << " (1..5)区间和:" << Query(1,1,5) << endl;
cout << " 把位置1的值加上100: " << endl;
update(1, 1, 100);
cout << " (1..5)区间最小值" << RminQ(1,1,5) << endl;
cout << " (1..5)区间最大值:" << RmaxQ(1,1,5) << endl;
cout << " (1..5)区间和:" << Query(1,1,5) << endl;
return 0;
}
/*
*总结一下线段树:
*(1)维护区间和,使得区间求和在O(log(n))的复杂度下完成
*(2)维护区间最小值,使得查询区间最小值在O(log(n))的复杂度下完成
*(3)维护区间最大值
****************************************************************
*(4)更新序列中某个值,也能使得树维护区间的最大,最小,和区间和。
*(5)基于区间和的应用,最小值得应用,例如序列的动态更新查询
*/
/**************************************************************************/
/*hihoCoder 1586
2017 ACM-ICPC 北京 网络赛 -I题
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3fffffff
const int MAXN=2e5;
typedef long long LL;
int arr[MAXN];
struct node {
LL left, right, min, max;//储存区间最小和最大值
}Tree[MAXN<<2];//线段树需要的空间为数组大小的四倍
void maintain(LL root) {//回溯时,对于每个节点,比较left、right的值的大小,更新
LL L = root<<1, R = (root<<1)+1;
Tree[root].max = max(Tree[L].max, Tree[R].max);
Tree[root].min = min(Tree[L].min, Tree[R].min);
}
void Build(LL root, LL start, LL end) {
//left,right表示该节点记录的区间为[left,right]
Tree[root].left = start;
Tree[root].right = end;
if(start == end) {//start等于end,区间只有一个元素,节点记录该单元素
Tree[root].max = arr[start];
Tree[root].min = arr[start];
return;
}
//递归构造左右子树
LL mid = (start+end)>>1;
Build(root<<1, start, mid);
Build((root<<1)+1, mid+1, end);
//上方递归完后,此根节点的左右子树已建好,即可确定此节点需保存的区间信息。
maintain(root);
}
void update(LL root, LL pos, LL value) {
//left == right 表示找到了叶子节点
if(Tree[root].left == Tree[root].right) {
Tree[root].max = value;
Tree[root].min = value;
return;
}
//显然,叶子节点值改变,需要更新所有包含此节点信息的节点
LL mid = (Tree[root].left + Tree[root].right)>>1;
if(pos <= mid)
update(root<<1, pos, value);
else
update((root<<1)+1, pos, value);
//同理
maintain(root);
}
LL RminQ(LL root, LL start, LL end) {
//查询区间和当前节点区间没有交集
if(start > Tree[root].right || end < Tree[root].left) return INF;
//当前节点区间包含在查询区间内
if(start <= Tree[root].left && Tree[root].right <= end) {
return Tree[root].min;
}
//分别从左右子树查询,返回两者查询结果的较小值
return min(RminQ(root<<1, start, end), RminQ((root<<1)+1, start, end));
}
LL RmaxQ(LL root, LL start, LL end) {
if(start > Tree[root].right || Tree[root].left > end) return -INF;
if(start <= Tree[root].left && Tree[root].right <= end) {
return Tree[root].max;
}
return max(RmaxQ(root<<1, start, end), RmaxQ((root<<1)+1, start, end));
}
/******************************************************************************/
//区间更新和建立,不同的题目
struct node {
LL l, r, sum, lazy, v;
}tree[MAXN<<2];
void maintain(LL root) {
LL L=root<<1, R=root<<1|1;
tree[root].sum = tree[L].sum + tree[R].sum;
}
void Build(LL root, LL start, LL end) {
tree[root].l = start;
tree[root].r = end;
tree[root].lazy = 0;
tree[root].v = 0;
if(start == end) {
tree[root].sum = 1;
return ;
}
LL mid = (start+end)>>1;
Build(root<<1, start, mid);
Build(root<<1|1, mid+1, end);
maintain(root);
}
void update(LL root, LL X, LL Y, LL Z) { //重点是更新, 其他很简单
if(tree[root].l == X && tree[root].r == Y) { // 如果此时区间的范围与需要查询的区间的范围刚好相等,修改此区间的信息后,
tree[root].v = Z;//不继续向下更新
tree[root].lazy = 1;
tree[root].sum = (Y-X+1)*Z;
return ;
}
LL mid = (tree[root].l+tree[root].r)>>1;
if(tree[root].lazy == 1) {//如果此时遇到了lazy==1的区间(说明此区间下面的分支还没更新过)
tree[root].lazy = 0;//lazy改为0,更新下面的区间(注意:这里只向下更新一级)
update(root<<1, tree[root].l, mid, tree[root].v);//因为左下一级的l,r肯定分别等于 上一级的tree[root].l , mid;
update(root<<1|1, mid+1, tree[root].r, tree[root].v);
tree[root].v = 0;//v改为0
}
if(mid >= Y) {//如果需要更新的区间在左区间;更新左区间
update(root<<1, X, Y, Z);
}else if(mid < X) {
update(root<<1|1, X, Y, Z);
}else {
update(root<<1, X, mid, Z);//要更新的区间在tree[root].l和tree[root].r之间,分别更新
update(root<<1|1, mid+1, Y, Z);
}
maintain(root);//更新上层
}
/*********************************************************************************/
int main() {
int T;
scanf("%d",&T);
while(T--) {
int n;
scanf("%d",&n);
n = 1 << n;
for(int i = 1; i <= n; i++) scanf("%lld",&arr[i]);
Build(1,1,n);
int Q;
long long tmp, bg, ed;
scanf("%d",&Q);
for(int i = 0; i < Q; i++) {
scanf("%lld%lld%lld",&tmp, &bg, &ed);
if(tmp==1) {
LL minNum = RminQ(1,bg+1,ed+1);
LL maxNum = RmaxQ(1,bg+1,ed+1);
printf("%lld\n",min(maxNum*maxNum,min(minNum*minNum,minNum*maxNum)));
}else {
update(1, bg+1, ed);
}
}
}
return 0;
}
/****************************************************************************************/
- ACM 线段树模板(模板)
- 线段树模板
- hdu_1166_线段树模板
- 线段树模板
- 线段树模板 poj2777
- 线段树模板
- 线段树模板
- 线段树-模板
- 线段树模板
- 线段树模板
- 线段树模板
- Hdu1166-- 线段树模板
- 线段树模板
- 线段树模板
- 线段树模板
- 线段树模板
- 线段树模板
- 线段树模板
- IA-32处理器基本功能3
- C语言中的熄灯问题extended lights out(枚举)POJ1222//乱用函数返回值会遭报应QAQ
- POJ 3009.Curling 2.0
- CenterOS设置静态IP
- Non-resolvable import POM: Failure to find Dalston.RC1 in was cached in the local repository
- 线段树模板
- OpenCV 自学笔记33. 计算图像的均值、标准差和平均梯度
- Linux平台生成AWR报告
- 数据分析过程示例
- 树莓派-硬件和功能-功耗
- 每日一练=20171115
- 蓝桥杯 基础练习 十六进制转八进制
- 我理解的AOP!
- 一种排序