POJ - 3468 和 POJ - 2823两道线段树模板题

POJ 3468

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100005;
typedef long long LL;

int n, q;
LL a[N];					//a[N]储存原数组
LL  lazy[N << 2];			//空间应该开区间的四倍
	//!!!懒惰标记(在节点上标记该区间内的所有节点的增量,非必要时不必更新区间内点的sum,以减小时间复杂度 
struct Tree{
	int l, r;
	LL sum;//如果有其他的目标值比如max,需要在pushup中更新 
	int mid(){	return (l + r) >> 1;}
}tree[N<<2];		

//更新节点信息 
void PushUp(int rt){//节点rt 
	tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;//父节点的sum = 两个子节点sum之和 
}

//下推懒惰标记
void PushDown(int rt,int m){//节点rt,区间长度m 
	if(lazy[rt]){
		//下推懒惰标记 
		lazy[rt << 1] += lazy[rt];
		lazy[rt << 1 | 1] += lazy[rt];
		//向下更新sum值 
		tree[rt << 1].sum += lazy[rt] * (m - (m >> 1));
		tree[rt << 1 | 1].sum += lazy[rt] * (m >> 1);
		//重置“根”节点的懒惰标记 
		lazy[rt] = 0;
	}
}

//建树
void build(int l, int r, int rt){//区间左端点l,区间右端点r,节点rt 
	tree[rt].l = l;
	tree[rt].r = r;
	lazy[rt] = 0;
	if (l == r)	{//当区间缩减到点时 赋予节点的sum 
		tree[rt].sum = a[l];
		return;
	}
	int m = tree[rt].mid();//tree[].mid()求区间中值函数 
	
	//构建左右子树 
	build(l, m, (rt << 1));
	build(m + 1, r, (rt << 1 | 1));
	
	//更新节点 
	PushUp(rt);
}

//区间修改:目标区间内每个点的sum都增加c 
void update(LL c, int l, int r, int rt){
			//所有点增量c,目标区间左端点l,目标区间右端点r,节点rt 
			
//如果刚好存在一个节点的区间与目标区间重合 
	if(tree[rt].l==l && tree[rt].r==r){
		
		//!!!懒惰标记(在节点上标记该区间内的所有节点的增量,非必要时不必更新区间内点的sum,以减小时间复杂度 
		lazy[rt] += c;
		tree[rt].sum += c*(r - l + 1);
		return;
	}
	 
//节点的区间并不能与目标区间重合 
	//如果已经下推到点(无论是否有懒惰标记,都不必更新sum,以减小时间复杂度 
	if(tree[rt].l == tree[rt].r)	return;
	
	int m = tree[rt].mid();
	//下推懒惰标记 
	PushDown(rt, tree[rt].r - tree[rt].l + 1);
	//如果目标区间的右端点  <=  节点区间的中值 
	if (r <= m)		update(c, l, r, rt << 1);//专门更新左子树 
	//如果目标区间的左端点  >  节点区间的中值 
	else if(l > m)	update(c, l, r, rt << 1 | 1);//专门个更新右子树 
	//如果目标区间涵盖节点区间的中值 
	else {
		update(c, l, m, rt << 1);
		update(c, m + 1, r, rt << 1 | 1);
	}
	PushUp(rt);
}
 
//求目标区间和 
LL Query(int l, int r, int rt){
		//目标区间左端点l,目标区间右端点r,节点rt 
		
//如果节点区间刚好和目标区间重合 
	if (l==tree[rt].l && r==tree[rt].r){
		return tree[rt].sum;
	}
	
//节点区间不与目标区间重合 
	int m = tree[rt].mid();
	//为了求和需要下推懒惰标记,和更新一些必要节点的sum 
	PushDown(rt, tree[rt].r - tree[rt].l + 1);
	LL res = 0;
	//目标区间的右端点 <= 节点区间中值 
	if(r <= m)		res += Query(l, r, rt << 1);//向左缩减节点区间 
	//目标区间的左端点 > 节点区间的中值 
	else if(l > m)	res += Query(l, r, rt << 1 | 1);//向右缩减节点区间 
	//目标区间涵盖了节点区间的中值 
	else{
		res += Query(l, m, rt << 1);
		res += Query(m + 1, r, rt << 1 | 1);
	}
	return res;
}

int main(){
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
        scanf("%lld", a + i);
    build(1, n, 1);
    char s;
    int l, r, c;
    while(q--){
        getchar();
        scanf("%c%d%d", &s, &l, &r);
        if(s=='C'){
            scanf("%d", &c);
            update(c, l, r, 1);
        } 
        else
            printf("%lld\n", Query(l, r, 1));
    }
    return 0;
}

POJ 2823

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1000005;

int n, q;
int a[N];
struct node{
	int l, r, min, max;
    int mid(){	return (l + r) >> 1;}
}node[N<<2];

void PushUp(int i){
	node[i].min = min(node[i << 1].min, node[(i << 1) | 1].min);
	node[i].max = max(node[i << 1].max, node[(i << 1) | 1].max);
}

void build(int l, int r, int i){
	node[i].l = l; node[i].r = r;
	if (l == r){
		node[i].max = node[i].min = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
	PushUp(i);
}

int Min(int l, int r, int rt){
    if (l==node[rt].l && r==node[rt].r)
		return node[rt].min;
	int m = node[rt].mid();
	int res = 0;
	if(r <= m)		res = Min(l, r, rt << 1);
	else if(l > m)	res = Min(l, r, rt << 1 | 1); 
    else
        res = min(Min(l, m, rt << 1), Min(m + 1, r, rt << 1 | 1));
    return res;
}
int Max(int l, int r, int rt){
    if (l==node[rt].l && r==node[rt].r)
		return node[rt].max;
	int m = node[rt].mid();
	int res = 0;
	if(r <= m)		res = Max(l, r, rt << 1);
	else if(l > m)	res = Max(l, r, rt << 1 | 1); 
    else
        res = max(Max(l, m, rt << 1), Max(m + 1, r, rt << 1 | 1));
    return res;
}

int main(){
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
        scanf("%d", a + i);
    build(1, n, 1);
    
    printf("%d", Min(1, q, 1));
    for (int i = 2; i <= n - q + 1; i++)
        printf(" %d", Min(i, i + q - 1, 1));
    printf("\n%d", Max(1, q, 1));
    for (int i = 2; i <= n - q + 1; i++)
        printf(" %d", Max(i, i + q - 1, 1));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值