【线段树单点更新区间修改】查询修改复杂度都是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;
}