线段树
线段树是一棵二叉搜索树,它储存的是一个区间的信息。下面是一个简单的线段树。
由上图可得,
1、每个节点的左孩子区间范围为[l,mid],右孩子为[mid+1,r] (mid=(l+r)/2)
2、对于结点k,左孩子结点为2k,右孩子为2k+1,这符合完全二叉树的性质
废话少说,下面是线段树的基本操作:
struct node
{
int l,r,w;//l,r分别表示区间左右端点,w表示区间和
}tree[400000];
先用结构体构建一个树,其实也不是一定要建一个结构体,你也可以构建几个单独的数组来建树;
建树
void build(int l,int r,int k)
{
tree[k].l=l;tree[k].r=r;
if(l==r)//叶子节点 {
scanf("%d",&tree[k].w);
return ;
}
int m=(l+r)/2;
build(l,m,k*2);//左孩子
build(m+1,r,k*2+1);//右孩子
tree[k].w=tree[k*2].w+tree[k*2+1].w;//状态合并,此结点的w=两个孩子的w之和
k就是上面辣个图的红色的数字,l和r就是代表一个区间的左右段,也就是上面图中蓝色的数字。关于这个mid的求法有些童鞋可能有点迷惑,比如mid=(1+3)/2=2,然后左边1-2,右边3-3,那构建出来的树不就右边相比于左边是缺了一点的吗?没关系,有几个k没被处理到也没关系,就把它空在那里是没有影响的,只要保证符合左孩子是 2k 右孩子是 2k+1 就可以了。
可能还有些童鞋对这个建树不大理解,那你可以举几个例子,自己按着这个函数的思路走一遍就会理解的。
单点查询
void ask(int k)
{
if(tree[k].l==tree[k].r) //当前结点的左右端点相等,是叶子节点,是最终答案 {
ans=tree[k].w;
return ;
}
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) ask(k*2);//目标位置比中点靠左,就递归左孩子
else ask(k*2+1);//反之,递归右孩子
}
这就是单点查询的操作,我们要查找编号为m的树是什么,然后从ask(1)太太太太太爷爷开始往下找到这个为m-m的孙子(比如找3,一共有10个,那找的顺序为1-10 —>1-5—>1-3—>3-3—>ans取3的值),当然也可以定义为int ask(int k) ,我这就不多写了。
单点修改
void add(int k){
if(tree[k].l==tree[k].r)//找到目标位置
{ tree[k].w+=y;
return;
}
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) add(k*2);
else add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;//所有包含结点k的结点状态更新
}
和单点查询思路差不多,w指的是区间所有数的和。一般线段树都有类似与w这样储存区间信息的数,这里只不过储存的是区间和。
区间查询
void sum(int k){
if(tree[k].l>=x&&tree[k].r<=y) {
ans+=tree[k].w;
return ;
}
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) sum(k*2);
if(y>m) sum(k*2+1);
}
ans储存的就是所求区间[x,y]的和,当然这个函数也可以设为int类型。如果对这种sum函数里面又有一个sum这样套来套去不理解的,最好的方法就是举个栗子从sum(1)开始套一遍直到最后结果出来,然后你就会理解了。
区间修改
区间修改是改一个区间,但是如果你一开始就一个一个去改的话,可能会浪费很多时间,所以我们用一个标记(数字)来标记这个区间,代表区间里面的值都要进行这个标记所代表的操作,这个标记也叫做 懒标记。(一般需要区间修改时才会用到懒标记)
代码需要两个函数,一个为:
懒标记下穿代码:f为懒标记,其余变量与前面含义一致。
void down(int k) {
tree[k*2].f+=tree[k].f;
tree[k*2+1].f+=tree[k].f;
tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
tree[k].f=0;
}
另一个为:
Ⅲ 完整的区间修改代码:
void add(int k)
{
if(tree[k].l>=a&&tree[k].r<=b)//当前区间全部对要修改的区间有用
{
tree[k].w+=(tree[k].r-tree[k].l+1)*x;//(r-1)+1区间点的总数
tree[k].f+=x;
return;
}
if(tree[k].f) down(k);//懒标记下传。只有不满足上面的if条件才执行,所以一定会用到当前节点的子节点
int m=(tree[k].l+tree[k].r)/2;
if(a<=m) add(k*2);
if(b>m) add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;//更改区间状态
}
这里是对区间[a,b]里的每个数加x,大家注意看,是区间的l>=a且区间的r<=b,是指当前区间在范围[a,b]里面在对这个区间加上x*(这个区间的数的个数),然后对这个区间加一个懒标记x,如果日后其他操作会涉及到这个区间的里面去,那就会进行这个down吧懒标记移到他的左右儿子那里。
接下来是几个题目:
hdu1754: I Hate It
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
Input
本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。
当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output
对于每一次询问操作,在一行里面输出最高成绩。
Sample Input
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5
Sample Output
5
6
5
9
简单的线段树题目,用到了单点查询和区间查询,不像前面的w那样存区间和,这题我们存区间最大值。
#include<iostream>
#include<algorithm>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
struct node
{
int l,r,maxx;
}tree[900005];
int n,m,a,b;
void build(int k,int l,int r)//建树
{
tree[k].l=l;
tree[k].r=r;
if(l==r) {
cin>>tree[k].maxx;
return ;
}
int mid=(l+r)/2;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tree[k].maxx=max(tree[2*k].maxx,tree[2*k+1].maxx);//存区间最大和
}
void change(int k)//单点修改
{
if(tree[k].l==tree[k].r) {
if(tree[k].l==a)
tree[k].maxx=b;
return ;
}
int mid=(tree[k].l+tree[k].r)/2;
if(a<=mid) change(2*k);
else change(2*k+1);
tree[k].maxx=max(tree[2*k].maxx,tree[2*k+1].maxx);
}
int find(int k)//区间查询
{ int ans1=0,ans2=0;
if(tree[k].l>=a&&tree[k].r<=b) {
return tree[k].maxx;
}
int mid=(tree[k].l+tree[k].r)/2;
if(a<=mid) ans1=max(ans1,find(2*k));
if(b>mid) ans2=max(ans2,find(2*k+1));
return max(ans1,ans2);
}
int main()
{ IOS;
char s;
while(cin>>n>>m)
{
build(1,1,n);
for(int i=1;i<=m;i++) {
cin>>s>>a>>b;
if(s=='Q') {
int sum=find(1);
cout<<sum<<endl;
}
else {
change(1);
}
}
}
return 0;
}
Codevs 1082:
题目描述 Description
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
输出描述 Output Description
对于每个询问输出一行一个答案
样例输入 Sample Input
3
1
2
3
2
1 2 3 2
2 2 3
样例输出 Sample Output
9
数据范围
1<=n<=200000
1<=q<=200000
考查区间修改和区间查询,这里就要用到懒标记了。
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 200005
typedef long long LL;
struct node{
int l,r,f;
LL w;
}tree[maxn<<2];
int n,q,op,a,b,c;
void build(int k,int l,int r){
tree[k].l=l;
tree[k].r=r;
if(l==r){
scanf("%d",&tree[k].w);
return;
}
int mid=(l+r)/2;
build(k<<1,l,mid);
build((k<<1)+1,mid+1,r);
tree[k].w=tree[k<<1].w+tree[(k<<1)+1].w;
}
void down(int k){//懒标记下传
tree[k<<1].f+=tree[k].f;
tree[(k<<1)+1].f+=tree[k].f;
tree[k<<1].w+=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1);
tree[(k<<1)+1].w+=tree[k].f*(tree[(k<<1)+1].r-tree[(k<<1)+1].l+1);
tree[k].f=0;
}
void change_interval(int k){//区间修改
if(tree[k].l>=a&&tree[k].r<=b){
tree[k].w+=c*(tree[k].r-tree[k].l+1);
tree[k].f+=c;
return;
}
if(tree[k].f)
down(k);
int mid=(tree[k].l+tree[k].r)/2;
if(a<=mid)
change_interval(k<<1);
if(b>mid)
change_interval((k<<1)+1);
tree[k].w=tree[k<<1].w+tree[(k<<1)+1].w;
}
LL ask_interval(int k){//区间查询
LL ans=0;
if(tree[k].l>=a&&tree[k].r<=b){
ans+=tree[k].w;
return ans;
}
if(tree[k].f)
down(k);
int mid=(tree[k].l+tree[k].r)/2;
if(a<=mid)
ans+=ask_interval(k<<1);
if(b>mid)
ans+=ask_interval((k<<1)+1);
return ans;
}
int main()
{
scanf("%d",&n);
memset(tree,0,sizeof(tree));
build(1,1,n);
scanf("%d",&q);
while(q--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&a,&b,&c);
change_interval(1);
}
else{
scanf("%d%d",&a,&b);
LL ans=ask_interval(1);
printf("%lld\n",ans);
}
}
return 0;
}
poj2777 Count Color :
有一块很长的板,长度为L厘米,L是一个正整数,所以我们可以把板均匀地分成L段,它们用1,2。。。L从左到右,每根都有1厘米长。现在我们要给电路板上色-一段只有一种颜色。我们可以在板上做以下两个操作:
-
"C A B C“用C色将板从A段涂到B段。
-
"P A B“输出A段和B段(包括)之间绘制的不同颜色的数量。
在我们的日常生活中,我们用很少的词来描述一种颜色(红、绿、蓝、黄……),所以你可能会认为不同颜色的总数T很小。为了简单起见,我们将颜色的名称表示为颜色1,颜色2。。。一开始,木板被涂成了颜色1。现在剩下的问题就交给你了。
Input
First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains “C A B C” or “P A B” (here A, B, C are integers, and A may be larger than B) as an operation defined previously.
Output
Ouput results of the output operation in order, each line contains a number.
Sample Input
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
Sample Output
2
1
这题我们需要用到二进制的知识,首先颜色种类并不多,我们可以用二进制存有哪些颜色在这个区间比如000000010代表只有2号颜色,如果对位运算符|和>>和<<不懂的,可以去百度查看。
#include<iostream>
using namespace std;
int n,m,o,a,b,c,ans;
struct mlp
{
int l,r,w;
bool f;
}tree[300000];
void build(int k,int l,int r)
{
tree[k].l=l;
tree[k].r=r;
tree[k].w=1;
tree[k].f=1;
if(l==r) {
return ;
}
int mid=(l+r)/2;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
}
void down(int k)
{
tree[2*k].w=tree[k].w;
tree[2*k+1].w=tree[k].w;
tree[2*k].f=tree[2*k+1].f=1;
tree[k].f=0;
}
void change(int k)
{
if(tree[k].l>=a&&tree[k].r<=b) {
tree[k].w=(1<<(c-1));
tree[k].f=1;
return ;
}
if(tree[k].w==(1<<(c-1))) return ;
if(tree[k].f) down(k);
int mid=(tree[k].l+tree[k].r)/2;
if(a<=mid) change(2*k);
if(b>mid) change(2*k+1);
tree[k].w=tree[2*k].w|tree[2*k+1].w;
}
void find(int k)
{
if(tree[k].l>=a&&tree[k].r<=b) {
ans=ans|tree[k].w;
return ;
}
if(ans==tree[k].w) return ;
if(tree[k].f) down(k);
int mid=(tree[k].l+tree[k].r)/2;
if(a<=mid) find(2*k);
if(b>mid) find(2*k+1);
tree[k].w=tree[2*k].w|tree[2*k+1].w;
}
//int find(int k)
//{ int ans,ans1,ans2;
// ans=ans1=ans2=0;
// if(tree[k].l>=a&&tree[k].r<=b) {
// ans=tree[k].w;
// return ans;
// }
// if(tree[k].f) down(k);
// int mid=(tree[k].l+tree[k].r)/2;
// if(a<=mid) ans1=find(2*k);
// if(b>mid) ans2=find(2*k+1);
// ans=ans1|ans2;
// return ans;
//}
int solve(int k)
{
int ans=0;
while(k) {
if(k%2==1) {
ans++;
}
k/=2;
}
return ans;
}
int main()
{ cin>>n>>m>>o;
char s;
build(1,1,n);
for(int i=1;i<=o;i++) {
cin>>s;
if(s=='C') {
cin>>a>>b>>c;
if(a>b) swap(a,b);
change(1);
}
else {
cin>>a>>b;
if(a>b) swap(a,b);
ans=0;
find(1);
cout<<solve(ans)<<endl;
}
}
return 0;
}
如果上面的题目你都懂了,那么现在告诉你,线段树还有一种题型,就是需要用到区间合并,请看下题:
**SPOJ - GSS1 Can you answer these queries I **
You are given a sequence A[1], A[2], …, A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defined as follows:
Query(x,y) = Max { a[i]+a[i+1]+…+a[j] ; x ≤ i ≤ j ≤ y }.
Given M queries, your program must output the results of these queries.
Input
The first line of the input file contains the integer N.
In the second line, N numbers follow.
The third line contains the integer M.
M lines follow, where line i contains 2 numbers xi and yi.
Output
Your program should output the results of the M queries, one query per line.
Input:
3
-1 2 3
1
1 2
Output:
2
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,x,y;
struct mmp
{
int sum,gss,lgss,rgss;
int l,r;
}tree[400001];
void build(int k,int l,int r)
{ tree[k].l=l;
tree[k].r=r;
if(l==r) {
cin>>tree[k].sum;
tree[k].lgss=tree[k].gss=tree[k].rgss=tree[k].sum;
return ;
}
int mid=(l+r)/2;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tree[k].sum=tree[2*k].sum+tree[2*k+1].sum;
tree[k].lgss=max(tree[2*k].lgss,tree[2*k].sum+tree[2*k+1].lgss);
tree[k].rgss=max(tree[2*k+1].sum+tree[2*k].rgss,tree[2*k+1].rgss);
tree[k].gss=max(max(tree[2*k].gss,tree[2*k+1].gss),tree[2*k].rgss+tree[2*k+1].lgss);
}
mmp find(int k,int x,int y)
{
if(tree[k].l==x&&tree[k].r==y) {
return tree[k];
}
int mid=(tree[k].l+tree[k].r)/2;
if(y<=mid) return find(2*k,x,y);
else if(x>mid) return find(2*k+1,x,y);
else {
mmp left,right,sum;
left=find(2*k,x,mid);
right=find(2*k+1,mid+1,y);
sum.sum=left.sum+right.sum;
sum.lgss=max(left.lgss,left.sum+right.lgss);
sum.rgss=max(right.sum+left.rgss,right.rgss);
sum.gss=max(max(left.gss,right.gss),left.rgss+right.lgss);
return sum;
}
}
int main()
{ while(cin>>n)
{ build(1,1,n);
cin>>m;
for(int i=1;i<=m;i++) {
cin>>x>>y;
cout<<find(1,x,y).gss<<endl;
}
}
return 0;
}
如果你对这操作不理解的话,那可以自己举个栗子,然后按着函数自己在纸上或脑海里把函数遍历的流程走一遍,你就能明白其中的奥义了。 就是我懒得打字了
最后一道题,这道题挺复杂的,我这个菜鸟当时是向另一个大佬请教才写出来,但出了点小错误,寻找了几个小时才发现是少写了一个return (崩溃)!
ZBOJ 1858序列操作
Description
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0 3 a b 询问[a, b]区间内总共有多少个1 4 a b 询问[a, b]区间内最多有多少个连续的1 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?
Input
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0 < = op < = 4,0 < = a < = b)
Output
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
Sample Input
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
Sample Output
5
2
6
5
Hint
对于30%的数据,1<=n, m<=1000 对于100%的数据,1< = n, m < = 100000
#include<iostream>
#include<algorithm>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ls 2*k
#define rs 2*k+1
using namespace std;
struct mmp
{
int l,r;
int f,pos;
int sum,gss[2],lgss[2],rgss[2];
}tree[400005];
int n,m;
void build(int k,int l,int r)
{ tree[k].l=l;tree[k].r=r;
tree[k].f=-1;tree[k].pos=0;
if(l==r) {
cin>>tree[k].sum ;
tree[k].gss[0] = tree[k].lgss[0] = tree[k].rgss[0] = !tree[k].sum;
tree[k].gss[1] = tree[k].lgss[1] = tree[k].rgss[1] = tree[k].sum;
return ;
}
int mid=(l+r)/2;
build(ls, l, mid);
build(rs, mid + 1, r);
tree[k].sum = tree[ls].sum + tree[rs].sum;
for(int i = 0; i < 2; i++)
{
tree[k].gss[i] = max(max(tree[ls].gss[i], tree[rs].gss[i]), tree[ls].rgss[i] + tree[rs].lgss[i]);
tree[k].lgss[i] = (tree[ls].lgss[i] == tree[ls].r - tree[ls].l + 1) ? (tree[ls].lgss[i] + tree[rs].lgss[i]) : tree[ls].lgss[i];
tree[k].rgss[i] = (tree[rs].rgss[i] == tree[rs].r - tree[rs].l + 1) ? (tree[rs].rgss[i] + tree[ls].rgss[i]) : tree[rs].rgss[i];
}
}
void change(mmp &u, int op)
{
int len = u.r - u.l + 1;
if(op < 2)
{
u.sum = op ? len : 0;
u.gss[op] = u.lgss[op] = u.rgss[op] = len;
u.gss[!op] = u.lgss[!op] = u.rgss[!op] = 0;
u.f = op; u.pos = 0;
}
else
{
u.sum = len - u.sum;
swap(u.gss[0], u.gss[1]);
swap(u.lgss[0], u.lgss[1]);
swap(u.rgss[0], u.rgss[1]);
if(u.f == -1) u.pos ^= 1;
else u.f ^= 1, u.pos = 0;
}
}
void down(int k)
{
if(!tree[k].pos && tree[k].f == -1) return ;
int op = tree[k].pos ? 3 : tree[k].f;
change(tree[ls], op); change(tree[rs], op);
tree[k].pos = 0; tree[k].f = -1;
}
void update(int k,int x,int y,int op)
{
if(x <= tree[k].l && tree[k].r <= y)
{
change(tree[k], op);
return ;
}
down(k);
int mid = tree[k].l + tree[k].r >> 1;
if(x <= mid) update(ls, x, y, op);
if(y > mid) update(rs, x, y, op);
tree[k].sum = tree[ls].sum + tree[rs].sum;
for(int i = 0; i < 2; i++)
{
tree[k].gss[i] = max(max(tree[ls].gss[i], tree[rs].gss[i]), tree[ls].rgss[i] + tree[rs].lgss[i]);
tree[k].lgss[i] = (tree[ls].lgss[i] == tree[ls].r - tree[ls].l + 1) ? (tree[ls].lgss[i] + tree[rs].lgss[i]) : tree[ls].lgss[i];
tree[k].rgss[i] = (tree[rs].rgss[i] == tree[rs].r - tree[rs].l + 1) ? (tree[rs].rgss[i] + tree[ls].rgss[i]) : tree[rs].rgss[i];
}
}
mmp query(int k, int x, int y)
{
if(x <= tree[k].l && tree[k].r <= y) return tree[k];
down(k);
int mid = tree[k].l + tree[k].r >> 1;
if(y <= mid) return query(ls, x, y);
else if(x > mid) return query(rs, x, y);
else
{
mmp left = query(ls, x, y), right = query(rs, x, y);
mmp res;
res.sum = left.sum + right.sum;
for(int i = 0; i < 2; i++)
{
res.gss[i] = max(max(left.gss[i],right.gss[i]), left.rgss[i] + right.lgss[i]);
res.lgss[i] = (left.lgss[i] == left.r - left.l + 1) ? (left.lgss[i] + right.lgss[i]) : left.lgss[i];
res.rgss[i] = (right.rgss[i] == right.r - right.l + 1) ? (right.rgss[i] + left.rgss[i]) : right.rgss[i];
}
return res;
}
}
int main()
{ IOS;
cin>>n>>m;
build(1,1,n);
// for(int i = 1; i <= 10; i++)
// cout << query(1, i, i).sum << ' ';
// cout << endl;
int op,l,r;
while(m--)
{
cin>>op>>l>>r;
l++;r++;
if(op < 3)
{
update(1, l, r, op);
// for(int i = 1; i <= 10; i++)
// cout << query(1, i, i).sum << ' ';
// cout << endl;
}
else
{
mmp res = query(1, l, r);
if(op == 3) cout << res.sum << endl;
else cout << res.gss[1] << endl;
}
}
return 0;
}
补充:
tree[k].sum = tree[ls].sum + tree[rs].sum;
for(int i = 0; i < 2; i++)
{
tree[k].gss[i] = max(max(tree[ls].gss[i], tree[rs].gss[i]), tree[ls].rgss[i] + tree[rs].lgss[i]);
tree[k].lgss[i] = (tree[ls].lgss[i] == tree[ls].r - tree[ls].l + 1) ? (tree[ls].lgss[i] + tree[rs].lgss[i]) : tree[ls].lgss[i];
tree[k].rgss[i] = (tree[rs].rgss[i] == tree[rs].r - tree[rs].l + 1) ? (tree[rs].rgss[i] + tree[ls].rgss[i]) : tree[rs].rgss[i];
}
代码里反复出现的这个代码,如果你嫌麻烦或觉得原代码很难看,可以把这个单独写成一个函数,比如:
void pushup(node &u, node l, node r)
{
u.sum = l.sum + r.sum;
for(int i = 0; i < 2; i++)
{
u.maxv[i] = max(max(l.maxv[i], r.maxv[i]), l.maxr[i] + r.maxl[i]);
u.maxl[i] = (l.maxl[i] == l.r - l.l + 1) ? (l.maxl[i] + r.maxl[i]) : l.maxl[i];
u.maxr[i] = (r.maxr[i] == r.r - r.l + 1) ? (r.maxr[i] + l.maxr[i]) : r.maxr[i];
}
}
感谢那位教我这道题的zhao大佬!
如果有朝一日我有空闲的没事,我会对这个博客进行一点点补充;