An easy problem B

Time Limit: 2000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)

Problem Description

N个数排成一列,每个数的大小为1或者0。有两种操作,第一种操作是把一段区间内的每个数异或1,第二种操作是询问区间内最长连续1的长度。

Input

第一行一个整数N(1≤N≤100000),表示N个数。第二行N个数。接下来一行一个整数M(1≤M≤100000),表示M个操作,接下来M行每行三个整数K,L,R。K=1表示把L到R这段区间的数全部异或上1,K=0表示询问L到R这段区间内最长连续1的长度。

Output

对于每个询问,输出对应的答案,每个询问占一行。

Sample Input

5

0 1 0 0 1

5

0 1 4

1 1 1

0 1 4

1 3 4

0 1 4

Sample Output

1

2

4


解题心得:

  1. 这个题考的就是一个线段树的区间合并问题外加一个lazy标记。其实这个题比较烦,要分比较多的情况,还很容易写bug。
  2. 先不说区间里面的0-1反转问题,就只是说建树和区间合并。首先要将区间合并起来(也就是向上更新的部分pushup),就要看区间合并包括几个部分。第一个,两个小的区间合并成一个大的区间,大的区间左方的最长连续1的部分就是这个大区间左子树的左方连续1部分,但是还没完,有一种特殊情况,当左子树全是1的时候大的区间的左方连续1是左子树的长度加上右子树的左方连续1的长度。大区间右方连续1的部分和左方的算法一样。还有就是大的区间的中间的连续的最大的连续1的长度,它由左子树的右方连续1的长度加上右子树左方连续1的长度。最后将三个最长的连续1区间比较一下得出最长的连续1区间。
  3. 那么我们在树中就要维护,当前节点(线段)的长度(r-l+1),l和r的位置,最长的左、右连续1的最长长度,当前最长的连续1的最长长度,以及一个lazy标记,同时,既然最后还要0-1反转,那么不但要记录1还要记录0,这样在0-1反转的时候直接将记录的0和1的情况直接交换就行了。
  4. 最后说说lazy标记的问题,当要对当前的区间进行更新的时候,要将当前区间更新,将当前区间lazy标记,并不是只标记而不进行更新。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
struct node
{
int lsum1,rsum1,lsum2,rsum2,l,r,sum1,sum2,lazy,len;//sum1代表1的情况,sum2代表0的情况
} tree[maxn<<2];
int n,m; //lazy标记下移,0-1反转
void pushdown(int root)
{
if(!tree[root].lazy)
return;
tree[root<<1].lazy ^= 1;
tree[root<<1|1].lazy ^= 1;
swap(tree[root<<1].sum1,tree[root<<1].sum2);
swap(tree[root<<1].lsum1,tree[root<<1].lsum2);
swap(tree[root<<1].rsum1,tree[root<<1].rsum2); swap(tree[root<<1|1].sum1,tree[root<<1|1].sum2);
swap(tree[root<<1|1].lsum1,tree[root<<1|1].lsum2);
swap(tree[root<<1|1].rsum1,tree[root<<1|1].rsum2); tree[root].lazy = 0;//当前的lazy标记需要取消
} //向上更新
void pushup(int root)
{
tree[root].lsum1=tree[root<<1].lsum1;
tree[root].lsum2=tree[root<<1].lsum2;
if(tree[root<<1].lsum1==tree[root<<1].len) tree[root].lsum1+=tree[root<<1|1].lsum1;//当最左边连续1的个数等于长度的时候
if(tree[root<<1].lsum2==tree[root<<1].len) tree[root].lsum2+=tree[root<<1|1].lsum2; tree[root].rsum1=tree[root<<1|1].rsum1;
tree[root].rsum2=tree[root<<1|1].rsum2;
if(tree[root<<1|1].rsum1==tree[root<<1|1].len) tree[root].rsum1+=tree[root<<1].rsum1;
if(tree[root<<1|1].rsum2==tree[root<<1|1].len) tree[root].rsum2+=tree[root<<1].rsum2; tree[root].sum1 = max(max(tree[root<<1].sum1, tree[root<<1|1].sum1), tree[root<<1].rsum1+tree[root<<1|1].lsum1);
tree[root].sum2 = max(max(tree[root<<1].sum2, tree[root<<1|1].sum2), tree[root<<1].rsum2+tree[root<<1|1].lsum2);
} void build_tree(int l,int r,int root)
{
tree[root].l = l,tree[root].r = r,tree[root].lazy = 0;
tree[root].len = r - l + 1;
if(l == r)
{
int x;
scanf("%d",&x);
if(x)
{
tree[root].lsum1 = tree[root].rsum1 = tree[root].sum1 = 1;
tree[root].lsum2 = tree[root].rsum2 = tree[root].sum2 = 0;
}
else
{
tree[root].lsum1 = tree[root].rsum1 = tree[root].sum1 = 0;
tree[root].lsum2 = tree[root].rsum2 = tree[root].sum2 = 1;
}
return ;
} int mid = (l + r) >> 1;
build_tree(l,mid,root<<1);
build_tree(mid+1,r,root<<1|1);
pushup(root);//记得向上更新
} void change(int a,int b,int l,int r,int root)
{
if(a <= l && b >= r)
{
swap(tree[root].sum1,tree[root].sum2);
swap(tree[root].lsum1,tree[root].lsum2);
swap(tree[root].rsum1,tree[root].rsum2);
tree[root].lazy ^= 1;//lazy标记
return ;
}
int mid = (l + r) / 2;
pushdown(root);//标记下移
if(b <= mid)
change(a,b,l,mid,root<<1);
else if(a > mid)
change(a,b,mid+1,r,root<<1|1);
else
{
change(a,mid,l,mid,root<<1);
change(mid+1,b,mid+1,r,root<<1|1);
}
pushup(root);
} int query(int a,int b,int l,int r,int root)
{
if(a <= l && b >= r)
return tree[root].sum1; int mid = (l + r)/2;
pushdown(root);
if(b <= mid)
return query(a,b,l,mid,root<<1);
else if(a > mid)
return query(a,b,mid+1,r,root<<1|1);
else
{
//看起来很多 就是左子树的最大值和右子树的最大值和两个子树合并起来的值取最大的一个
int m1 = query(a,mid,l,mid,root<<1);
int m2 = query(mid+1,b,mid+1,r,root<<1|1);
int m3 = max(m1,m2);
int m4 = min(tree[root<<1].rsum1,mid-a+1);
int m5 = min(b-mid,tree[root<<1|1].lsum1);
return max(m3,m4+m5);
}
pushup(root);
} int main()
{
while(scanf("%d",&n)!=EOF)
{
build_tree(1,n,1);
scanf("%d",&m);
while(m--)
{
int k,a,b;
scanf("%d%d%d",&k,&a,&b);
if(k)
change(a,b,1,n,1);
else
{
int ans = query(a,b,1,n,1);
printf("%d\n",ans);
}
}
}
return 0;
}

最新文章

  1. 开篇:IT软件人员学习的书籍 - IT软件人员书籍系列文章
  2. 微软云Azure Website 远程调试
  3. C#开源系统大汇总
  4. Excel 中单元格和范围的引用(即访问的表示方法)
  5. Python 描述符(descriptor) 杂记
  6. Robot Instructions
  7. sap 三代出口(BADI)的查找方法
  8. 快递查询API接口对接方法
  9. (译)ABP之Entities
  10. 解决在C#(.net)按字节数截取字符串最后出现乱码的问题
  11. Python爬虫入门教程 20-100 慕课网免费课程抓取
  12. RabbitMQ:MSVCR120.dll ,c000001d 错误
  13. 在 github 新建一个文件夹
  14. Elasticsearch 开启
  15. python 中的 metaclass
  16. com_pc-mcu
  17. Ubuntu 13.10 下安装搜狗输入法
  18. Python实现向s3共享存储上传和下载文件
  19. jackson springboot null节点忽略配置
  20. first-child伪类选择器

热门文章

  1. 软件模拟I2C时输入与输出切换
  2. SSRS-lookupSet-DataSet-分组查询
  3. SSIS 抽取excel出错:所请求的 OLE DB 访问接口 Microsoft.ACE.OLEDB.12.0 尚未注册
  4. 《从0到1学习Flink》—— Data Source 介绍
  5. wepy开发踩坑记录
  6. Control中的AOP实现非业务需求
  7. Java 面向对象,封装,继承
  8. python基础---有关nparray----切片和索引(一)
  9. 解决Chrome浏览器自动记录用户名和密码的黄色背景问题和该解决方法与tab切换至下一个input冲突的问题。
  10. ios 开发发布证书配置详细流程