区间更新,可以采用遍历点更新的方式,但是时间复杂度很高,故此引用了lazy,延迟思想:
- 如果一个线段树的划分区间属于更新区间,可以先将所有的操作“累加”在该区间,不需要在继续向下更新。
- 如果一个线段树的划分区间属于更新区间并且区间内的数值是一致的,那么可以先将操使用于该区间,而不需要继续向下更新,因为该区间内的所有数值是一致的。
引入两个函数:
- Push_down函数:当前的线段树划分区间不满足我们需要的条件(例如:1.不完全在更新区间内;2.区间内的数值不一致)。
- Push_up函数:如果子树的信息变更影响到了父亲,就需要对父亲信息进行更新,这个操作在点更新的线段树中也是存在的,只是没有单独作为一个更新函数拎出来。
配题:HDU 4902(前面废话一大堆故事,最后几行是题目)
题意:维护一个数组,经过一系列操作之后,输出数组,两个操作:
- 操作1:将区间l,r之间的数全部变为x
- 操作2:将区间l,r之间的所有大于x的元素赋值为x和该元素的Gcd
想法:采用保持划分区间数值一致的思想即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#define L(x) x << 1
#define R(x) (x << 1) | 1
using namespace std;
const int maxn = 100000 + 5;
int n, m;
struct NODE
{
int lft, rht;
int lazy;
int val;
int mid()
{
return (lft + rht) / 2;
}
};
NODE segtree[maxn*4];
int Gcd(int a, int b)
{
if (!b)
{
return a;
}
else
{
return Gcd(b, a%b);
}
}
void build_segtree(int cur_index, int lft, int rht)
{
segtree[cur_index].lft = lft;
segtree[cur_index].rht = rht;
segtree[cur_index].lazy = 0;
if (lft != rht)
{
int mid = segtree[cur_index].mid();
build_segtree(L(cur_index), lft, mid);
build_segtree(R(cur_index), mid+1, rht);
}
}
void Push_up(int cur_index)
{
if (segtree[L(cur_index)].val == segtree[R(cur_index)].val)
{
segtree[cur_index].val = segtree[L(cur_index)].val;
}
else
{
segtree[cur_index].val = -1;
}
}
void Push_down(int cur_index)
{
if (segtree[cur_index].lazy)
{
segtree[L(cur_index)].lazy = segtree[R(cur_index)].lazy = 1;
segtree[L(cur_index)].val = segtree[R(cur_index)].val = segtree[cur_index].val;
segtree[cur_index].lazy = 0;
}
}
void updata_seg1(int cur_index, int pos_lft, int pos_rht, int val)
{
int lft = segtree[cur_index].lft;
int rht = segtree[cur_index].rht;
if (pos_lft <= lft && rht <= pos_rht)
{
segtree[cur_index].lazy = 1;
segtree[cur_index].val = val;
return;
}
else
{
Push_down(cur_index);
int mid = segtree[cur_index].mid();
if (pos_lft <= mid) updata_seg1(L(cur_index), pos_lft, pos_rht, val);
if (pos_rht > mid) updata_seg1(R(cur_index), pos_lft, pos_rht, val);
Push_up(cur_index);
}
}
void updata_seg2(int cur_index, int pos_lft, int pos_rht, int val)
{
int lft = segtree[cur_index].lft;
int rht = segtree[cur_index].rht;
if (pos_lft <= lft && rht <= pos_rht && segtree[cur_index].val != -1)
{
if (segtree[cur_index].val > val)
{
segtree[cur_index].val = Gcd(segtree[cur_index].val, val);
segtree[cur_index].lazy = 1;
}
return;
}
else
{
Push_down(cur_index);
int mid = segtree[cur_index].mid();
if (pos_lft <= mid) updata_seg2(L(cur_index), pos_lft, pos_rht, val);
if (pos_rht > mid) updata_seg2(R(cur_index), pos_lft, pos_rht, val);
Push_up(cur_index);
}
}
void query_segtree(int cur_index)
{
int lft = segtree[cur_index].lft;
int rht = segtree[cur_index].rht;
if (lft == rht)
{
cout<< segtree[cur_index].val<< " ";
return;
}
else
{
Push_down(cur_index);
query_segtree(L(cur_index));
query_segtree(R(cur_index));
}
}
int main()
{
int T;
cin>> T;
while (T--)
{
cin>> n;
build_segtree(1, 1, n);
for (int i = 1; i <= n; i++)
{
int val;
cin>> val;
updata_seg1(1, i, i, val);
}
cin>> m;
for (int i = 1; i <= m; i++)
{
int t, l, r, x;
cin>> t>> l>> r>> x;
if (t == 1)
{
updata_seg1(1, l, r, x);
}
else
{
updata_seg2(1, l, r, x);
}
}
query_segtree(1);
cout<< endl;
}
return 0;
}