线段树:CDOJ1592-An easy problem B (线段树的区间合并)
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
解题心得:
- 这个题考的就是一个线段树的区间合并问题外加一个lazy标记。其实这个题比较烦,要分比较多的情况,还很容易写bug。
- 先不说区间里面的0-1反转问题,就只是说建树和区间合并。首先要将区间合并起来(也就是向上更新的部分pushup),就要看区间合并包括几个部分。第一个,两个小的区间合并成一个大的区间,大的区间左方的最长连续1的部分就是这个大区间左子树的左方连续1部分,但是还没完,有一种特殊情况,当左子树全是1的时候大的区间的左方连续1是左子树的长度加上右子树的左方连续1的长度。大区间右方连续1的部分和左方的算法一样。还有就是大的区间的中间的连续的最大的连续1的长度,它由左子树的右方连续1的长度加上右子树左方连续1的长度。最后将三个最长的连续1区间比较一下得出最长的连续1区间。
- 那么我们在树中就要维护,当前节点(线段)的长度(r-l+1),l和r的位置,最长的左、右连续1的最长长度,当前最长的连续1的最长长度,以及一个lazy标记,同时,既然最后还要0-1反转,那么不但要记录1还要记录0,这样在0-1反转的时候直接将记录的0和1的情况直接交换就行了。
- 最后说说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 (线段树的区间合并)的更多相关文章
- 线段树:CDOJ1597-An easy problem C(区间更新的线段树)
An easy problem C Time Limit: 4000/2000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...
- 线段树:CDOJ1591-An easy problem A (RMQ算法和最简单的线段树模板)
An easy problem A Time Limit: 1000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...
- POJ 2826 An Easy Problem? 判断线段相交
POJ 2826 An Easy Problem?! -- 思路来自kuangbin博客 下面三种情况比较特殊,特别是第三种 G++怎么交都是WA,同样的代码C++A了 #include <io ...
- 线段树: CDOJ1598-加帕里公园的friends(区间合并,单点更新)
加帕里公园的friends Time Limit: 3000/1000MS (Java/Others) Memory Limit: 131072/131072KB (Java/Others) 我还有很 ...
- HDU 5475(2015 ICPC上海站网络赛)--- An easy problem(线段树点修改)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5475 Problem Description One day, a useless calculato ...
- ACM学习历程—HDU5475 An easy problem(线段树)(2015上海网赛08题)
Problem Description One day, a useless calculator was being built by Kuros. Let's assume that number ...
- POJ 2826 An Easy Problem?!(线段交点+简单计算)
Description It's raining outside. Farmer Johnson's bull Ben wants some rain to water his flowers. Be ...
- hdu 5475 An easy problem(暴力 || 线段树区间单点更新)
http://acm.hdu.edu.cn/showproblem.php?pid=5475 An easy problem Time Limit: 8000/5000 MS (Java/Others ...
- HDU 5475 An easy problem 线段树
An easy problem Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pi ...
随机推荐
- python2 学习 数据类型和变量
数据类型和变量 数据类型 整数 Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1,100,-8080,0,等等. 计算机由于使用二进制,所以,有时 ...
- Spring 整合 Quartz 实现动态定时任务(附demo)
最近项目中需要用到定时任务的功能,虽然Spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大.在考虑之后,决定整合更为专业的Quartz来实现定时任务功能. 普通定时任务 首先 ...
- html学习笔记-XML
html学习笔记-XML Table of Contents 1. XML简介 2. XML用途 3. XML树结构 4. XML语法 5. XML元素 6. XML属性 7. XML验证 8. XM ...
- 一个例子说明Jsp三大重要内置对象的生命周期
此处Jsp的三大内置对象指:request,session以及application.他们共有的方法:setAttribute,getAttribute,方法名和方法作用都是相同的,但是作用范围不一样 ...
- Game Engine Architecture
- 将一个字符与对应Ascii码互转
package nicetime.com.practies; /** * Java中将一个字符与对应Ascii码互转 1 byte = 8bit 可以表示 0-127 */public class G ...
- HDU 3709 Balanced Number (数位DP)
题意: 找出区间内平衡数的个数,所谓的平衡数,就是以这个数字的某一位为支点,另外两边的数字大小乘以力矩之和相等,即为平衡数. 思路: 一开始以为需要枚举位数,枚举前缀和,枚举后缀和,一旦枚举起来就会M ...
- 随记:UWP开发中怎么使当前页面拓展到标题栏
public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); CoreAp ...
- BZOJ 2654: tree Kruskal+二分答案
2654: tree Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1863 Solved: 736[Submit][Status][Discuss ...
- JS中的作用域和作用域链
本文原链接:https://cloud.tencent.com/developer/article/1403589 前言 作用域(Scope) 1. 什么是作用域 2. 全局作用域和函数作用域 3. ...