线段树区间求和, 点更新
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;
}