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;
}

线段树:CDOJ1592-An easy problem B (线段树的区间合并)的更多相关文章

  1. 线段树:CDOJ1597-An easy problem C(区间更新的线段树)

    An easy problem C Time Limit: 4000/2000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...

  2. 线段树:CDOJ1591-An easy problem A (RMQ算法和最简单的线段树模板)

    An easy problem A Time Limit: 1000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...

  3. POJ 2826 An Easy Problem? 判断线段相交

    POJ 2826 An Easy Problem?! -- 思路来自kuangbin博客 下面三种情况比较特殊,特别是第三种 G++怎么交都是WA,同样的代码C++A了 #include <io ...

  4. 线段树: CDOJ1598-加帕里公园的friends(区间合并,单点更新)

    加帕里公园的friends Time Limit: 3000/1000MS (Java/Others) Memory Limit: 131072/131072KB (Java/Others) 我还有很 ...

  5. HDU 5475(2015 ICPC上海站网络赛)--- An easy problem(线段树点修改)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5475 Problem Description One day, a useless calculato ...

  6. ACM学习历程—HDU5475 An easy problem(线段树)(2015上海网赛08题)

    Problem Description One day, a useless calculator was being built by Kuros. Let's assume that number ...

  7. POJ 2826 An Easy Problem?!(线段交点+简单计算)

    Description It's raining outside. Farmer Johnson's bull Ben wants some rain to water his flowers. Be ...

  8. hdu 5475 An easy problem(暴力 || 线段树区间单点更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=5475 An easy problem Time Limit: 8000/5000 MS (Java/Others ...

  9. HDU 5475 An easy problem 线段树

    An easy problem Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pi ...

随机推荐

  1. memcache和iptables开启11211端口

    linux下安装完memcached后,netstat -ant | grep LISTEN 看到memcache用的11211端口已在监听状态,但建立php文件连接测试发现没有输出结果,iptabl ...

  2. NHibernate中创建User类报错问题

    前两天刚开始学习NHibernate架构,照着前辈的例子打了一遍运行之后没问题,然后自己创建了一个User的Model发现一运行就报User附近有错误,然后就检查,类写的没错用了virtual,Use ...

  3. 一个很好用的侧滑框架ICSDrawerController实现的 QQ 侧滑及换肤功能

    使用ICSDrawerController 实现侧滑功能 在ICSDrawerController 第三方上做了修改实现,QQ 点击头像打开关抽屉头像渐变的效果 - (void)hiddenHeadV ...

  4. git remote add 用法

    前一阵子,对于git remote add 的内容一直调错,现在明确一下: 这里是gitStack的用法:git remote add gitServerName http://ip/name(这里没 ...

  5. django之母版的继承

    模板继承示例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  6. SharePoint运行状况分析器有关磁盘空间不足的警告

    对于负责管理SharePoint内部部署安装的SharePoint管理员,SharePoint Health Analyzer是一款出色的工具.此功能不仅有助于解决服务器故障和服务失败的问题,还提供了 ...

  7. Installing Apache, PHP, and MySQL on Mac OS X

    I have installed Apache, PHP, and MySQL on Mac OS X since Leopard. Each time doing so by hand. Each ...

  8. ThinkPHP笔记——开启debug调试模式

    debug+trace模式可以查看开发过程中TP的错误信息,可以更好地帮助开发者debug.但是debug模式的开启还不是简单的在配置文件中中设置就可以的,经过查资料摸索,找到一种有效的方法. 首先在 ...

  9. cv2.minAreaRect() 生成最小外接矩形

    简介   使用python opencv返回点集cnt的最小外接矩形,所用函数为 cv2.minAreaRect(cnt) ,cnt是所要求最小外接矩形的点集数组或向量,这个点集不定个数.   cv2 ...

  10. Spring boot 集成ActiveMQ(包含双向队列实现)

    集百家之长,成一家之言.  1. 下载ActiveMQ https://mirrors.tuna.tsinghua.edu.cn/apache/activemq/5.15.9/apache-activ ...