题目链接:http://acm.uestc.edu.cn/#/problem/show/360
题目翻译:给出N个数字,Q个操作,如果输入操作类型是a,则【L,R】区间中的数字都要加上V。
否则就查询【L,R】区间内最长连续递增子序列的长度。一个区间,其两个子区间依据边界值对
两个区间进行合并。
Max数组维护任意一个区间的最长连续子序列长度。
lnum数组保存一个区间左边界的数值
rnum数组保存一个区间右边界的数值
lsum数组保存以当前区间左边界为开始的最长连续递增子序列的长度
rsum数组保存以当前区间右边界为开始的最长连续递增子序列的长度。
每次用子区间去更新父区间。
父区间左边界值是它左子区间左边界值
父区间右边界值是它右子区间右边界值
父区间的lsum和rsum我们先继承其左右孩子的。
如果不考虑左右孩子区间的拼接,父区间中最长连续递增子序列的长度应该是其子区间中的最大值。
如果发现父区间的左区间的右边界值小于父区间的右区间的左边界值,则两个区间可以拼接。
如果左区间整断连续递增,则才可以与右区间以左边界为开始的最长连续递增子序列拼接,成为父区间
以左边界开始的最长连续子序列长度。如果右区间整断连续递增,则才可以与左区间以右边界为结束的最长
连续递增子序列进行拼接。
然后拼接左区间以右边界为结束的最长连续递增序列和右区间以左边界为开始的最长连续递增序列。
最后查询的时候需要注意,因为我们是查到子区间就返回答案,所以子区间中连续字符串的位置不一定
就在边界,所以我们需要处理一下。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lchild left,mid,root<<1
#define rchild mid+1,right,root<<1|1
using namespace std;
const int maxn = 100010;
int lsum[maxn<<2],rsum[maxn<<2],Max[maxn<<2],lazy[maxn<<2];
long long lnum[maxn<<2],rnum[maxn<<2];
///更新当前节点的值
void push_up(int left,int right,int root) {
lnum[root] = lnum[root<<1]; ///区间的左边界是其左区间的左边界
rnum[root] = rnum[root<<1|1]; ///区间的有边界是其右区间的右边界
lsum[root] = lsum[root<<1]; ///以左端点为开始的连续递增序列长度是其左区间以左边界开始的连续递增序列长度
rsum[root] = rsum[root<<1|1]; ///以右断电为结束的连续递增序列长度是其右区间以有边界结束的连续递增序列长度
Max[root] = max(Max[root<<1],Max[root<<1|1]);
long long leftright = rnum[root<<1]; ///左区间的右侧数字
long long rightleft = lnum[root<<1|1]; ///右区间的左侧数字
int mid = (left+right)>>1;
///两个区间可能拼接在一起。
if(leftright<rightleft) {
if(lsum[root] == mid-left+1) {
lsum[root] += lsum[root<<1|1];
}
if(rsum[root] == right-mid) {
rsum[root] += rsum[root<<1];
}
Max[root] = max(Max[root],rsum[root<<1]+lsum[root<<1|1]);
}
}
void push_down(int root) {
if(lazy[root]) {
lazy[root<<1] += lazy[root];
lazy[root<<1|1] += lazy[root];
lnum[root<<1] += lazy[root];
rnum[root<<1] += lazy[root];
lnum[root<<1|1] += lazy[root];
rnum[root<<1|1] += lazy[root];
lazy[root] = 0;
}
}
void build(int left,int right,int root) {
lazy[root] = 0;
if(left == right) {
scanf("%lld",&lnum[root]);
rnum[root] = lnum[root];
Max[root] = lsum[root] = rsum[root] = 1;
return;
}
int mid = (left+right)>>1;
build(lchild);
build(rchild);
push_up(left,right,root);
}
void update(int L,int R,int add,int left,int right,int root) {
if(L<=left && right<=R) {
lnum[root] += add;
rnum[root] += add;
lazy[root] += add;
return;
}
push_down(root);
int mid = (left+right)>>1;
if(L<=mid) update(L,R,add,lchild);
if(R>mid) update(L,R,add,rchild);
push_up(left,right,root);
}
int query(int L,int R,int left,int right,int root) {
if(L<=left && right<=R) {
return Max[root];
}
push_down(root);
int ans = 1;
int mid = (left+right)>>1;
if(L<=mid) ans = max(ans,query(L,R,lchild));
if(R>mid) ans = max(ans,query(L,R,rchild));
if(rnum[root<<1] < lnum[root<<1|1]) {
ans = max(ans,min(R,mid+lsum[root<<1|1])-max(L,mid-rsum[root<<1]+1)+1);
}
return ans;
}
int main() {
int T,Case=0;
scanf("%d",&T); ///T组测试数据
while(T--) {
int N,Q;
scanf("%d%d",&N,&Q); ///N个数字,Q次操作
build(1,N,1);
char op;
int L,R,V;
printf("Case #%d:\n",++Case);
while(Q--) {
scanf(" %c",&op);
if(op == 'a') {
scanf("%d%d%d",&L,&R,&V);
update(L,R,V,1,N,1);
} else {
scanf("%d%d",&L,&R);
int ans = query(L,R,1,N,1);
printf("%d\n",ans);
}
}
}
return 0;
}