【线段树】

【线段树单点更新区间修改】查询修改复杂度都是log(n),建树复杂度2n(有2n-1个结点)

合并上来的区间不会有重复段

【堆写法(结构体)】需要4*n个节点

#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MAXN 200010
struct NODE{
	int x,y,mx;
}node[MAXN<<2];
int a[MAXN];

void bulid(int u, int x, int y)
{
    if(x == y)//叶子节点直接赋值
    {
        node[u].x = x, node[u].y = y;
		node[u].mx = a[x];
        return;
    }
    int m = (x+y)>>1;
    bulid(u<<1,x,m);//u的左儿子编号为u<<1,右儿子为u<<1|1;
    bulid(u<<1|1,m+1,y);
    node[u].mx = max(node[u<<1].mx, node[u<<1|1].mx);
	node[u].x = x, node[u].y = y;
}
int ql, qr;//查询区间
int query(int u)
{
    if(ql <= node[u].x && node[u].y <= qr) return node[u].mx;//当前节点包含查询区间
    int m = (node[u].x+node[u].y)>>1, ans = -INF;
    if(ql <= m) ans = max(ans, query(u<<1));//向左走
    if(m < qr) ans = max(ans, query(u<<1|1));//向右走
    return ans;
}
int p,v;//修改a[p] = v
void update(int u)
{
    if(node[u].x == node[u].y)//叶子结点直接更新
    {
        node[u].mx = v;
        return;
    }
    int m = (node[u].x+node[u].y)>>1;
    if(p <= m) update(u<<1);
    else update(u<<1|1);
    node[u].mx = max(node[u<<1].mx, node[u<<1|1].mx);
}

 

【树写法】需要4n个节点

#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MAXN 200010
int mx[MAXN<<2], a[MAXN];

void bulid(int u, int x, int y)
{
    if(x == y)//叶子节点直接赋值
    {
        mx[u] = a[x];
        return;
    }
    int m = (x+y)>>1;
    bulid(u<<1,x,m);//u的左儿子编号为u<<1,右儿子为u<<1|1;
    bulid(u<<1|1,m+1,y);
    mx[u] = max(mx[u<<1], mx[u<<1|1]);
}
int ql, qr;//查询区间
int query(int u, int x, int y)
{
    if(ql <= x && y <= qr) return mx[u];//当前节点包含查询区间
    int m = (x+y)>>1, ans = -INF;
    if(ql <= m) ans = max(ans, query(u<<1,x,m));//向左走
    if(m < qr) ans = max(ans, query(u<<1|1,m+1,y));//向右走
    return ans;
}
int p,v;//修改a[p] = v
void update(int u, int x, int y)
{
    if(x == y)//叶子结点直接更新
    {
        mx[u] = v;
        return;
    }
    int m = (x+y)>>1;
    if(p <= m) update(u<<1,x,m);
    else update(u<<1|1, m+1,y);
    mx[u] = max(mx[u<<1], mx[u<<1|1]);
}


【区间修改区间查询】必须要用一个变量临时保存延时更新才能把复杂度控制在log(n)

【堆写法】

#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MAXN 100010
#define lc u<<1
#define rc u<<1|1
struct NDOE{
	int x,y;//左右区间
	int sum;//附加信息
	int setv;//需要修改的值(标记),-1不需要修改
}node[MAXN<<2];

inline void push_up(int u)//向上更新
{
	node[u].sum = node[lc].sum+node[rc].sum;
}
void bulid(int u, int x, int y)//建树
{
	node[u].x = x, node[u].y = y;
	node[u].setv = -1;
	if(x == y)
	{
		node[u].sum = 1;
		return;
	}
	int m = (x+y)>>1;
	bulid(lc,x,m);
	bulid(rc,m+1,y);
	push_up(u);
}
void push_down(int u)//向下更新
{
	if(~node[u].setv)//如果被标记过需要更新
	{
		node[lc].setv = node[rc].setv = node[u].setv;//把修改值传递下去
		node[lc].sum = node[u].setv*(node[lc].y-node[lc].x+1);//<span style="color:#ff0000;">如果是add操作的话必须是*node[u].add
</span>		node[rc].sum = node[u].setv*(node[rc].y-node[rc].x+1);
		node[u].setv = -1;
	}
}
int ql,qr,v;//修改区间[ql,qr]为v
void update(int u)
{
	int x = node[u].x, y = node[u].y;
	if(ql <= x && y <= qr)//只更新到被覆盖区间(不更新此区间下面的节点,查询的时候再更新)
	{
		node[u].sum = (y-x+1)*v;
		node[u].setv = v;
		return;
	}
	push_down(u);
	int m = (x+y)>>1;
	if(ql <= m) update(lc);
	if(qr > m) update(rc);
	push_up(u);
}
int query(int u)
{
	int x = node[u].x, y = node[u].y;
	if(ql <= x && y <= qr)
		return node[u].sum;
	push_down(u);//只比单点更新的区间查询多一个向下更新
	int m = (x+y)>>1, ans = 0;
	if(ql <= m) ans += query(lc);
	if(qr > m) ans += query(rc);
	return ans;
}



 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值