线段树的区间查询有两种方式,不同写法的功能不同,要多加注意
两者区别很小,前者(l, r)初始区间得到保留,而后者将(l, r)拆散求和
但是其原理都是将大区间拆散求和,主要是因为形式不同对于不同性质问题求解麻烦与否有很大影响
I.
int query(int l, int r, int L, int R, int root)
{
int res = 0;
if(l <= L && r >= R) return sum[root];
int mid = (L + R) >> 1;
if(l <= mid) res += query(l, r, L, mid, root<<1);
if(r > mid) res += query(l, r, mid+1, R, root<<1|1);
return res;
}
II.
int Query(int l, int r, int L, int R, int root)
{
if(l<=L && r>=R)
return sum[root];
int mid = (L + R) >> 1;
if(r <= mid) return Query(l, r, Lson);
else if(l > mid) return Query(l, r, Rson);
else return Query(l, mid, Lson) + Query(mid+1, r, Rson);
}
Problem I
#include
#include
#include
using namespace std;
const int MAX=50010;
#define Lson L,mid,root<<1 //遇到Lson的时候强制替换为后面的语句
#define Rson mid+1,R,root<<1|1
int n,sum[MAX<<2];
void Pushup(int root) //把当前结点的信息更新到父节点
{
sum[root]=sum[root<<1]+sum[root<<1|1];
}
void Build(int L,int R,int root)
{
if(L==R)
{
scanf("%d",&sum[root]);
return ;
}
int mid=(L+R)>>1;
Build(Lson); //左孩子
Build(Rson); //右孩子
Pushup(root);
}
void Update(int q,int val,int L,int R,int root) //在根为root,区间为[L,R]中的线段树修改结点p的值增加val
{
if(L==R)
{
sum[root]+=val;
return ;
}
int mid=(L+R)>>1;
if(q<=mid) Update(q,val,Lson); //说明p在左结点
else Update(q,val,Rson); //说明p在右结点
Pushup(root);
}
int Query(int l, int r, int L, int R, int root)
{
if(l<=L && r>=R)
return sum[root];
int mid = (L + R) >> 1;
if(r <= mid) return Query(l, r, Lson);
else if(l > mid) return Query(l, r, Rson);
else return Query(l, mid, Lson) + Query(mid+1, r, Rson);
}
int main()
{
int a,b,Case,num=1;
scanf("%d",&Case);
while(Case--)
{
printf("Case %d:\n",num++);
scanf("%d",&n);
Build(1,n,1);
char op[10];
while(scanf("%s",op))
{
if(op[0]=='E') break;
scanf("%d%d",&a,&b);
if(op[0]=='A') Update(a,b,1,n,1);
if(op[0]=='S') Update(a,-b,1,n,1);
if(op[0]=='Q') printf("%d\n",Query(a,b,1,n,1));
}
}
return 0;
}
Problem II
#include
#include
#define maxn 100000 + 10
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
struct Node
{
int sum, lazy;
} T[maxn<<2];
void PushUp(int rt)
{
T[rt].sum = T[rt<<1].sum + T[rt<<1|1].sum;
}
void PushDown(int L, int R, int rt)
{
int mid = (L + R) >> 1;
T[rt<<1].sum = T[rt].lazy * (mid - L + 1);
T[rt<<1|1].sum = T[rt].lazy * (R - mid);
T[rt<<1].lazy = T[rt].lazy;
T[rt<<1|1].lazy = T[rt].lazy;
T[rt].lazy = 0;
}
void Build(int L, int R, int rt)
{
if(L == R)
{
scanf("%d", &T[rt].sum);
return ;
}
int mid = (L + R) >> 1;
Build(Lson);
Build(Rson);
PushUp(rt);
}
void Update(int l, int r, int v, int L, int R, int rt)
{
if(l<=L && r>=R)
{
T[rt].lazy = v;
T[rt].sum = v * (R - L + 1);
return ;
}
int mid = (L + R) >> 1;
if(T[rt].lazy) PushDown(L, R, rt);
if(r <= mid) Update(l, r, v, Lson);
else if(l > mid) Update(l, r, v, Rson);
else
{
Update(l, mid, v, Lson);
Update(mid+1, r, v, Rson);
}
PushUp(rt);
}
int Query(int l, int r, int L, int R, int rt)
{
if(l<=L && r>=R)
return T[rt].sum;
int mid = (L + R) >> 1;
if(T[rt].lazy) PushDown(L, R, rt);
if(r <= mid) return Query(l, r, Lson);
else if(l > mid) return Query(l, r, Rson);
return Query(l, mid, Lson) + Query(mid + 1, r, Rson);
}
int main()
{
int n, q;
scanf("%d", &n);
Build(1, n, 1);
scanf("%d", &q);
int a, b, c, d;
while(q--)
{
scanf("%d%d%d", &a, &b, &c);
if(a)
{
scanf("%d", &d);
Update(b, c, d, 1, n, 1);
}
else printf("%d\n", Query(b, c, 1, n, 1));
}
return 0;
}
Problem III
离散型与连续型的区别:
1.叶子节点:在离散型中,叶子节点是[i, i],而连续性中是[i, i + 1];
2.分解区间:在离散型中,一段区间是分解成为[l, m], [m + 1, r],而在连续型中,是分解成为[l, m], [m, r];
3.其他所有类似的判定问题。
#include
#include
#include
#include
#include
using namespace std;
#define maxn 100005
#define lson L, mid, rt<<1
#define rson mid, R, rt<<1|1
int a[maxn], b[maxn];
int lazy[maxn<<2];
int N, L;
int left_bound = 1, right_bound;
void init()
{
memset(lazy, -1, sizeof(lazy));
right_bound = 0;
}
void read_compress()
{
set<int> s;
for(int i=1; i<=N; i++)
{
scanf("%d%d", &a[i], &b[i]);
s.insert(a[i]);
s.insert(b[i]);
}
map<int, int> m;
for(set<int>::iterator it=s.begin(); it!=s.end(); it++)
m[*it] = ++right_bound;
for(int i=1; i<=N; i++)
{
a[i] = m[a[i]];
b[i] = m[b[i]];
}
}
void pushdown(int L, int R, int rt)
{
if(lazy[rt] >= 0)
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
void update(int l, int r, int v, int L, int R, int rt)
{
if(l<=L && r>=R)
{
lazy[rt] = v;
return ;
}
int mid = (L+R)>>1;
if(lazy[rt] >= 0) pushdown(L, R, rt);
if(r <= mid) update(l, r, v, lson);
else if(l >= mid) update(l, r, v, rson);
else
{
update(l, mid, v, lson);
update(mid, r, v, rson);
}
}
void query(int l, int r, int L, int R, int rt, set<int> &s)
{
if(l<=L && r>=R && lazy[rt]>=0)
{
s.insert(lazy[rt]);
return ;
}
int mid = (L+R)>>1;
if(lazy[rt] >= 0) pushdown(L, R, rt);
if(r <= mid) query(l, r, lson, s);
else if(l >= mid) query(l, r, rson, s);
else
{
query(l, mid, lson, s);
query(mid, r, rson, s);
}
}
int main()
{
while(~scanf("%d%d", &N, &L))
{
init();
read_compress();
int cnt = 0;
for(int i=1; i<=N; i++)
update(a[i], b[i], ++cnt, left_bound, right_bound, 1);
cnt = 0;
set<int> s;
for(int i=1; i<=N; i++)
query(a[i], b[i], left_bound, right_bound, 1, s);
printf("%d\n", s.size());
}
return 0;
}
Problem IIII
#include
#include
#include
#include
using namespace std;
#define maxn 100000 + 10
#define lson L, mid, rt<<1
#define rson mid+1, R, rt<<1|1
int n, k;
int a[maxn];
int ans;
struct Node
{
int mi, ma;
}T[maxn<<2];
void pushup(int rt)
{
int l = rt<<1, r = rt<<1|1;
T[rt].ma = max(T[l].ma, T[r].ma);
T[rt].mi = min(T[l].mi, T[r].mi);
}
void build(int L, int R, int rt)
{
if(L == R)
{
T[rt].ma = T[rt].mi = a[L];
return ;
}
int mid = (L + R) >> 1;
build(lson);
build(rson);
pushup(rt);
}
///注意树的节点与区间节点不要混淆
void query(int l, int r, int v, int L, int R, int rt)
{
if(L == R)
{
if(abs(T[rt].mi - v) >= k)
{
if(ans == -1 || ans < L)
ans = L;
}
return ;
}
int mid = (L + R) >> 1;
if(r > mid)
if(abs(T[rt<<1|1].mi - v) >= k || abs(T[rt<<1|1].ma - v) >= k)
query(l, r, v, rson);
if(ans == -1 && l <= mid)
if(abs(T[rt<<1].mi - v) >= k || abs(T[rt<<1].ma - v) >= k)
query(l, r, v, lson);
}
int d[maxn];
long long sum;
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
sum = 1;
scanf("%d%d", &n, &k);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
build(1, n, 1);
d[1] = 1;
for(int i=2; i<=n; i++)
{
ans = -1;
query(1, i, a[i], 1, n, 1);
if(ans == -1)
d[i] = d[i-1];
else d[i] = max(d[i-1], ans + 1);
sum += i - d[i] + 1;
}
printf("%I64d\n", sum);
}
return 0;
}
The New
Go For it
线段树区间修改 维护和值、最大值、最小值
#include
#include
#define maxn 100000 + 10
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
int min(int a, int b) {return aint max(int a, int b) {return a>b ? a : b;}
struct Node
{
int sum, Min, Max, lazy;
} T[maxn<<2];
void PushUp(int rt)
{
T[rt].sum = T[rt<<1].sum + T[rt<<1|1].sum;
T[rt].Min = min(T[rt<<1].Min, T[rt<<1|1].Min);
T[rt].Max = max(T[rt<<1].Max, T[rt<<1|1].Max);
}
void PushDown(int L, int R, int rt)
{
int mid = (L + R) >> 1;
int t = T[rt].lazy;
T[rt<<1].sum = t * (mid - L + 1);
T[rt<<1|1].sum = t * (R - mid);
T[rt<<1].Min = T[rt<<1|1].Min = t;
T[rt<<1].Max = T[rt<<1|1].Max = t;
T[rt<<1].lazy = T[rt<<1|1].lazy = t;
T[rt].lazy = 0;
}
void Build(int L, int R, int rt)
{
if(L == R)
{
scanf("%d", &T[rt].sum);
T[rt].Min = T[rt].Max = T[rt].sum;
return ;
}
int mid = (L + R) >> 1;
Build(Lson);
Build(Rson);
PushUp(rt);
}
void Update(int l, int r, int v, int L, int R, int rt)
{
if(l==L && r==R)//修改区间值
{
T[rt].lazy = v;
T[rt].sum = v * (R - L + 1);
T[rt].Min = T[rt].Max = v;
return ;
}
int mid = (L + R) >> 1;
if(T[rt].lazy) PushDown(L, R, rt);//向下更新一级
if(r <= mid) Update(l, r, v, Lson);
else if(l > mid) Update(l, r, v, Rson);
else
{
Update(l, mid, v, Lson);
Update(mid+1, r, v, Rson);
}
PushUp(rt);
}
int Query(int l, int r, int L, int R, int rt)
{
if(l==L && r== R)
{
printf("(%d, %d)---Min: %d Max: %d Sum: %d \n", L, R, T[rt].Min, T[rt].Max, T[rt].sum);
return T[rt].sum;
}
int mid = (L + R) >> 1;
if(T[rt].lazy) PushDown(L, R, rt);
if(r <= mid) return Query(l, r, Lson);
else if(l > mid) return Query(l, r, Rson);
return Query(l, mid, Lson) + Query(mid + 1, r, Rson);
}
int main()
{
int n, q;
scanf("%d", &n);
Build(1, n, 1);
scanf("%d", &q);
int a, b, c, d;
while(q--)
{
scanf("%d%d%d", &a, &b, &c);
if(a)
{
scanf("%d", &d);
Update(b, c, d, 1, n, 1);
}
else printf("%d\n", Query(b, c, 1, n, 1));
}
return 0;
}
/*
6
1 2 3 4 5 6
3
0 1 4
1 2 3 0
0 1 4
*/
Problem v
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define lson L, mid, rt<<1
#define rson mid+1, R, rt<<1|1
#define maxn 100000 + 10
long long a[maxn];
int n, m;
struct Node
{
long long M[2][8];
}T[maxn<<2];
void pushup(int rt)
{
int l = rt<<1, r = rt<<1|1;
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
{
T[rt].M[i][j] = max(max(T[l].M[i][j], T[r].M[i][j]), max(T[l].M[i][0]+T[r].M[1][j], T[l].M[i][9]+T[r].M[0][j]));
}
}
void build(int L, int R, int rt)
{
if(L == R)
{
scanf("%I64d", &a[L]);
if(L & 1)
{
T[rt].M[1][10] = a[L];
T[rt].M[0][0] = -INF;
}
else
{
T[rt].M[0][0] = a[L];
T[rt].M[1][11] = -INF;
}
T[rt].M[1][0] = -INF;
T[rt].M[0][12] = -INF;
return ;
}
int mid = (L + R) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void update(int t, int v, int L, int R, int rt)
{
if(L == R)
{
if(L & 1)
T[rt].M[1][13] = v;
else
T[rt].M[0][0] = v;
return ;
}
int mid = (L + R) >> 1;
if(t <= mid) update(t, v, lson);
else update(t, v, rson);
pushup(rt);
}
Node query(int l, int r, int L, int R, int rt)
{
Node tmp;
if(l == L && r == R)
{
tmp = T[rt];
return tmp;
}
int mid = (L + R) >> 1;
if(r <= mid) return query(l, r, lson);
else if(l > mid) return query(l, r, rson);
else
{
Node ltmp = query(l, mid, lson);
Node rtmp = query(mid+1, r, rson);
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
{
tmp.M[i][j] = max(max(ltmp.M[i][j], rtmp.M[i][j]), max(ltmp.M[i][0]+rtmp.M[1][j], ltmp.M[i][14]+rtmp.M[0][j]));
}
return tmp;
}
}
int main()
{
int kase;
scanf("%d", &kase);
while(kase--)
{
scanf("%d%d", &n, &m);
build(1, n, 1);
for(int i=0; iint t, a, b;
scanf("%d%d%d", &t, &a, &b);
if(t == 0)
{
long long ans = -INF;
Node tmp = query(a, b, 1, n, 1);
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
{
ans = max(ans, tmp.M[i][j]);
}
printf("%I64d\n", ans);
}
else
{
update(a, b, 1, n, 1);
}
}
}
}