线段树区间合并板子

胡乱分析

区间合并操作指的是在给定的区间内,计算出例如10111011中的最大1的个数

分组解析

build操作

build操作与之前的求值的build操作一样,初始化的时候ls,rs,ms都是r+1-l初始化区间都是1

1
2
3
4
5
6
7
8
9
10
void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;
t[p].ls=t[p].rs=t[p].ms=r+1-l;
if(l==r)
return;
int mid=(t[p].l+t[p].r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}

change操作

这个题是单点的更改,change操作与之前不同的地方在于push_up操作原先的push_up仅仅只是把值修改一下这里修改的是区间的长度,所以有所不同
首先更新ls ls=左的ls
rs=右的rs
ms=等于左的ms右的ms和中间右左左右的加和的最大值
其中如果ls溢出那么加上右的左
rs溢出同理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void change(int p,int x,int y) //change函数
{
if(t[p].l==t[p].r&&t[p].l==x)
{
t[p].ls=t[p].rs=t[p].ms=y;
return;
}
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)
change(p<<1,x,y);
else
change(p<<1|1,x,y);
//push up原先的push up是更改左右孩子的值之类的这里要进行区间的合并更改
t[p].ls=t[p<<1].ls; //当前的左等于左孩子的左
t[p].rs=t[p<<1|1].rs;//当前的右等于右孩子的右
t[p].ms=max(max(t[p<<1].ms,t[p<<1|1].ms),t[p<<1].rs+t[p<<1|1].ls);//当前的总和等于左,右,中的最大值
if(t[p<<1].ls==t[p<<1].r+1-t[p<<1].l)//如果左溢出加上右的左
t[p].ls+=t[p<<1|1].ls;
if(t[p<<1|1].rs==t[p<<1|1].r+1-t[p<<1|1].l)//如果右溢出加上左的右
t[p].rs+=t[p<<1].rs;
}

sum操作

这里的sum求的是包含这个点的最大的区间长度所以如果到点了或者满了或者没有那么就返回即可
然后分左右合并,如果满了就加上即可跟change的感觉差不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int sum(int p,int x)
{
if(t[p].l==t[p].r||t[p].ms==0||t[p].ms==t[p].r+1-t[p].l)
return t[p].ms;
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)
{
if(x>=t[p<<1].r+1-t[p<<1].rs)//如果溢出加上右边
return sum(p<<1,x)+sum(p<<1|1,mid+1);
else
return sum(p<<1,x);
}
else
{
if(x<=t[p<<1|1].l+t[p<<1|1].ls-1)//如果溢出加上左边
return sum(p<<1|1,x)+sum(p<<1,mid);
else
return sum(p<<1|1,x);
}
}

完整代码(hdu-1540)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <bits/stdc++.h>
using namespace std;
struct node
{
int l,r,ls,rs,ms;
}t[200005];
stack<int> st;
void build(int p,int l,int r) //递归构造树
{
t[p].l=l;t[p].r=r;
t[p].ls=t[p].rs=t[p].ms=r+1-l;
if(l==r)
return;
int mid=(t[p].l+t[p].r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
void change(int p,int x,int y) //change函数
{
if(t[p].l==t[p].r&&t[p].l==x)
{
t[p].ls=t[p].rs=t[p].ms=y;
return;
}
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)
change(p<<1,x,y);
else
change(p<<1|1,x,y);
//push up原先的push up是更改左右孩子的值之类的这里要进行区间的合并更改
t[p].ls=t[p<<1].ls; //当前的左等于左孩子的左
t[p].rs=t[p<<1|1].rs;//当前的右等于右孩子的右
t[p].ms=max(max(t[p<<1].ms,t[p<<1|1].ms),t[p<<1].rs+t[p<<1|1].ls);//当前的总和等于左,右,中的最大值
if(t[p<<1].ls==t[p<<1].r+1-t[p<<1].l)//如果左溢出加上右的左
t[p].ls+=t[p<<1|1].ls;
if(t[p<<1|1].rs==t[p<<1|1].r+1-t[p<<1|1].l)//如果右溢出加上左的右
t[p].rs+=t[p<<1].rs;
}
int sum(int p,int x)
{
if(t[p].l==t[p].r||t[p].ms==0||t[p].ms==t[p].r+1-t[p].l)
return t[p].ms;
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)
{
if(x>=t[p<<1].r+1-t[p<<1].rs)//如果溢出加上右边
return sum(p<<1,x)+sum(p<<1|1,mid+1);
else
return sum(p<<1,x);
}
else
{
if(x<=t[p<<1|1].l+t[p<<1|1].ls-1)//如果溢出加上左边
return sum(p<<1|1,x)+sum(p<<1,mid);
else
return sum(p<<1|1,x);
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
while(cin>>n>>m)
{
memset(t,0,sizeof(t));
build(1,1,n);
while(m--)
{
char c;
int x;
cin>>c;
if(c=='D')
{
cin>>x;
change(1,x,0);
st.push(x);
}
else if(c=='R')
{
change(1,st.top(),1);
st.pop();
}
else
{
cin>>x;
cout<<sum(1,x)<<"\n";
}
}
}
}
就算是一分钱,也是对作者极大的支持
------ 本文结束 ------

版权声明

Baccano by baccano is licensed under a Creative Commons BY-NC-ND 4.0 International License.
baccano创作并维护的Baccano博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证
本文首发于baccano 博客( http://baccano.fun ),版权所有,侵权必究。

小游戏

---小游戏:要不要来选择一下自己可能的老婆?---

简易发声器

---简易的七键钢琴插件---

可以使用鼠标点击琴键也可以使用主键盘1-7或者小键盘的1-7来操作

那么现在开始吧

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
0%