线段树区间求和、点更新,区间求最大值、点更新与区间染色、离散化、lazy

线段树区间求和, 点更新

void build(int l, int r, int ret){
    int m;
    if(l == r){
        scanf("%d", &sum[ret]);
        return ;
    }
    m = (l+r)>>1;
    build(l, m, ret*2);
    build(m+1, r, ret*2+1);
    sum[ret] = sum[ret*2] + sum[ret*2+1];
}

void updata(int x, int y, int l, int r, int ret){
        int m;
        if(l == r){
            sum[ret] += y;
            return ;
        }
        m = (l+r)>>1;
        if(x <= m)
            updata(x, y, l, m, ret*2);
        else
            updata(x, y, m+1, r, ret*2+1);
        sum[ret] = sum[ret*2] + sum[ret*2+1];
}

int query(int L, int R, int l, int r, int ret){
        int ans, m;
        if(L <= l && r <= R){
            return sum[ret];
        }
        ans = 0;
        m = (l+r)>>1;
        if(L <= m) ans += query(L, R, l, m, ret*2);
        if(R >= m+1) ans += query(L, R, m+1, r, ret*2+1); //不可写为R>= m,例如L=1,R=3,m= 3时;
        return ans;//query会进入不该进入的部分, 再多几轮会出现 L>= l && r >= R, 进入死循环
}

区间求最大值、点更新

此处sum数组是指其中存的最大值, 复制的就放着不改了。

void build(int l, int r, int ret){
    int m;
    if(l == r){
        scanf("%d", &sum[ret]);
        return ;
    }
    m = (l+r)>>1;
    build(l, m, ret*2);
    build(m+1, r, ret*2+1);
    sum[ret] = max(sum[ret*2], sum[ret*2+1]);
}
void updata(int x, int y, int l, int r, int ret){
    int m;
    if(l == r){
        sum[ret] = y;
        return ;
    }
    m = (l+r)>>1;
    if(x <= m) updata(x, y ,l, m, ret*2);
    else updata(x, y, m+1, r, ret*2+1);
    sum[ret] = max(sum[ret*2], sum[ret*2+1]);
}
int query(int L, int R, int l, int r, int ret){
    int m, ans;
    if(L <= l && r <= R){
        return sum[ret];
    }
    ans = 0;
    m = (l+r)>>1;
    if(L <= m) ans = max(ans,query(L, R, l, m, ret*2));
    if(R >= m+1) ans = max(ans, query(L, R, m+1, r, ret*2+1));
    return ans;
}

线段树区间染色,离散化处理

区间染色, 延迟标记, 使用set统计数量

set<int> p;
void push_down(int ret){
    if(lazy[ret]){
        tree[ret<<1|1] = tree[ret<<1] = lazy[ret];
        lazy[ret<<1|1] = lazy[ret<<1] = lazy[ret];
        lazy[ret] = 0;
    }
}
void build(int l, int r, int ret){
    int m;
    tree[ret] = 0;
    lazy[ret] = 0;
    if(l == r) return ;
    m = (l+r) >> 1;
    build(l, m, ret*2);
    build(m+1, r, ret*2+1);
}
void update(int k, int L, int R, int l, int r, int ret){
    int m;
    if(L <= l && r <= R){
        tree[ret] = k;
        lazy[ret] = k;
        return  ;
    }
    push_down(ret);
     m = (l+r) >> 1;
    if(L <= m) update(k, L, R, l, m, ret<<1);
    if(R > m) update(k, L, R, m+1, r, ret<<1|1);
}
int query(int l, int r, int ret){
    int m;
    if(l == r){
        if(tree[ret] && !p.count(tree[ret])){
            p.insert(tree[ret]);
            return 1;
        }
        return 0;
    }
    push_down(ret);
    m = (l+r) >>1;
    return query(l, m ,ret<<1) + query(m+1, r, ret<<1|1);
}

离散化处理

先将值存入数组,排序后, 使用unique函数去重, 再将相邻两元素大于一的数中间插入一个中间数(先把中间数放在数组后面, 然后通过第二次排序实现)

关于unique

unique()函数是STL中得一个去重函数,在头文件中,unique的功能是去除相邻的重复元素(只保留一个),还有一个容易忽视的特性是它并不真正把重复的元素删除。
unique(a, a+n)返回的是a去重后的最后一个不重复的元素的下一个地址,之所以说比是真正把重复的元素删除,其实重复的元素在不重复的元素后面,依然保存到了原数组中,然后返回去重后的最后一个元素的下一地址。

 for(i = 1; i <= n; i++){
            scanf("%d %d", &s[i].x, &s[i].y);
            a[tt++] = s[i].x;
            a[tt++] = s[i].y;
        }
        sort(a, a+tt);
        tt = unique(a, a+tt) - a;
        temp = tt;
        for(i = 1; i < temp; i++){
            if(a[i] - a[i-1] > 1) a[tt++] = a[i-1] + 1;
        }
        sort(a, a+tt);

通过lower_bound函数二分查找数在数组中的下标, 返回第一个大于等于该数的下标。

for(i = 1; i <= n; i++){
            x = lower_bound(a, a+tt, s[i].x) - a;
            y = lower_bound(a, a+tt, s[i].y) - a;
            x++; y++;
            update(i, x, y, 1, tt, 1);
        }

线段树区间修改值,区间查询,(lazy区间标记更新)

int num[100001*4];
int lazy[100001*4];
void bulit(int l, int r,int ret){
	int m = (l+r)/2;
	lazy[ret] = 0;
	if(r == l){
		num[ret] = 1;
		return ;
	}
	bulit(l, m, ret*2);
	bulit(m+1, r, ret*2+1);
	num[ret] = num[ret*2] + num[ret*2+1];
}
void pushdown(int l, int r, int ret){
	if(lazy[ret]){
		lazy[ret*2] = lazy[ret*2+1] = lazy[ret];
		int m = (l+r)/2;
		num[ret*2] = (m-l+1)*lazy[ret]; 
		num[ret*2+1] = (r-(m+1)+1)*lazy[ret];
		lazy[ret] = 0;
	}
}
void change(int L, int R, int l, int r, int key, int ret){
	int m = (l+r)/2;
	if(L<= l&& r<= R){
		lazy[ret] = key;
		num[ret] = (r-l+1)*key;
		return ;
	}
	pushdown(l, r, ret);
	if(L<= m) change(L, R, l, m, key, ret*2);
	if(R> m) change(L, R, m+1, r, key, ret*2+1);
	num[ret] = num[ret*2] + num[ret*2+1];
}
int ans = 0;
int query(int L, int R, int l, int r, int ret){
	int ans = 0;
	int m = (l+r)/2;
	if(L <= l && r <= R){
        return num[ret];
    }
    pushdown(l, r, ret);
    ans = 0;
    m = (l+r)>>1;
    if(L <= m) ans += query(L, R, l, m, ret*2);
    if(R >= m+1) ans += query(L, R, m+1, r, ret*2+1); 
    return ans;
}

查询区间最大值和最小值的差值

#include <cstdio>
#include <algorithm>
using namespace std;
struct node{
	int maxx;
	int minn;
}num[50001*4];

void bulit(int l, int r, int ret){
	int m = (l+r)/2;
	if(l == r){
		scanf("%d", &num[ret].maxx);
		num[ret].minn = num[ret].maxx;
		return ;
	}
	bulit(l, m, ret*2);
	bulit(m+1, r, ret*2+1);
	num[ret].maxx = max(num[ret*2].maxx, num[ret*2+1].maxx);
	num[ret].minn = min(num[ret*2].minn, num[ret*2+1].minn);
}
int query_maxx(int L, int R, int l, int r, int ret){
	int ans = 0, m;
	if(L <= l && r <= R){
		ans = num[ret].maxx;
		return ans;
	} 
	m = (l+r)/2;
	if(L <= m) ans = max(ans, query_maxx(L, R, l, m, ret*2));	
	if(R > m) ans = max(ans, query_maxx(L, R, m+1, r, ret*2+1));
	return ans;	
}
int query_minn(int L, int R, int l, int r, int ret){
	int ans = 0x3f3f3f3f, m;
	if(L <= l && r <= R){
		ans = num[ret].minn;
		return ans;
	} 
	m = (l+r)/2;
	if(L <= m) ans = min(ans, query_minn(L, R, l, m, ret*2));	
	if(R > m) ans = min(ans, query_minn(L, R, m+1, r, ret*2+1));
	return ans;	
}

叠加lazy,减少lazy向下更新次数

#include <cstdio>
using namespace std;
const int maxn = 1e5 + 10;
const int mod = 10007;
struct node{
	int l, r;
	int v;
	int lazy;	
}num[maxn*4];
void pushup(int ret){
	if(num[ret<<1].lazy && num[ret<<1|1].lazy && num[ret<<1].v == num[ret<<1|1].v){
		num[ret].lazy = 1;
		num[ret].v = num[ret<<1].v;
		return ;
	}
	num[ret].lazy = 0;
}
void pushdown(int ret){
	if(num[ret].lazy){
		num[ret<<1].lazy = num[ret<<1|1].lazy = 1;
		num[ret<<1].v = num[ret<<1|1].v = num[ret].v;
		num[ret].lazy = 0;
	}
}
void build(int l, int r, int ret){
	int m = (l +r) >>1;
	num[ret].l = l;
	num[ret].r = r;
	num[ret].v = 0;
	num[ret].lazy = 1;
	if(l == r)
		return ;
	build(l, m, ret<<1);
	build(m+1, r, ret<<1|1); 
}
void update(int op, int l, int r, int v,int ret){
	if(l <= num[ret].l && num[ret].r <= r && num[ret].lazy == 1){
		if(op == 1)
			num[ret].v += v;
        else if (op == 2) 
			num[ret].v *= v;
        else 
			num[ret].v = v;
        num[ret].v %= mod;
        return;
	}
	pushdown(ret);
	int m = (num[ret].l + num[ret].r) >> 1;
	if(l <= m) update(op, l, r, v, ret<<1);
	if(m < r)  update(op, l, r, v, ret<<1|1);
	pushup(ret);
}
int query(int l, int r, int p, int ret){
	int ans = 0;
	if(l <= num[ret].l && num[ret].r <= r && num[ret].lazy == 1){
		int res = 1;
        for (int i = 0; i < p; i++)
            res *= num[ret].v, res %= mod;
        return res * (num[ret].r - num[ret].l + 1) % mod;
	}
	pushdown(ret);
	int m = (num[ret].l + num[ret].r) >> 1;
	if(l <= m) ans =(ans + query(l, r, p, ret<<1)) % mod;
	if(m < r) ans = (ans + query(l, r, p, ret<<1|1))%mod;
	return ans;
}
int main(){
	int ope, x, y, c;
	int m, n;
    while (~scanf("%d %d", &n, &m) && n && m)
    {
        build(1, n, 1);
        while (m--)
        {
            scanf("%d%d%d%d", &ope, &x, &y, &c);
            if (ope != 4)
                update(ope, x, y, c, 1);
            else printf("%d\n",query(x, y, c, 1));
        }
    }	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值