HDU 3397 Sequence operation (区间合并,操作比较多)
费了我一天半的时间,到处debug,后来才发现,主要是建树的时候只在叶子节点对lazy1和lazy2进行初始化了,父节点都没初始化。。。晕。
具体见代码吧。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#define lson rt<<1,L,mid
#define rson rt<<1|1,mid+1,R
/*
用两个lazy标记,lazy1标记01覆盖,lazy2标记异或(即取反)。
如果在lazy1标记之前,就已经有lazy2异或标记了,那么我们就可以直接去掉lazy2标记(赋值为0),直接进行置01标记;
如果在lazy2异或标记之前,就有01标记了,那么就需要处理一下,即对lazy1进行异或。 具体还是见代码吧,主要是操作繁琐了点
*/
using namespace std;
const int maxn=;
int t,n,m; struct Node{
int lsum[],rsum[],msum[]; //统计0/1的左连续的个数,右连续的个数,最大的连续个数
int num[]; //统计0/1的个数
int lazy1; //标记01覆盖
int lazy2; //标记取反
int len; //区间长度
}tree[maxn<<]; void pushUp(Node &rt,Node &ls,Node &rs){
rt.lsum[]=ls.lsum[];rt.rsum[]=rs.rsum[];
rt.lsum[]=ls.lsum[];rt.rsum[]=rs.rsum[]; rt.num[]=ls.num[]+rs.num[];
rt.num[]=ls.num[]+rs.num[];
if(ls.lsum[]==ls.len)
rt.lsum[]+=rs.lsum[];
if(rs.rsum[]==rs.len)
rt.rsum[]+=ls.rsum[];
rt.msum[]=ls.rsum[]+rs.lsum[];
rt.msum[]=max(rt.msum[],max(ls.msum[],rs.msum[])); if(ls.lsum[]==ls.len)
rt.lsum[]+=rs.lsum[];
if(rs.rsum[]==rs.len)
rt.rsum[]+=ls.rsum[];
rt.msum[]=ls.rsum[]+rs.lsum[];
rt.msum[]=max(rt.msum[],max(ls.msum[],rs.msum[]));
}
void changexor(Node &rt){
if(rt.lazy1!=-)
rt.lazy1^=; //如果之前有01标记,那么就对01标记异或一下即可
else
rt.lazy2^=; //否则对取反标记异或
swap(rt.num[],rt.num[]);
swap(rt.lsum[],rt.lsum[]);
swap(rt.rsum[],rt.rsum[]);
swap(rt.msum[],rt.msum[]);
} void pushDown(Node &rt,Node &ls,Node &rs,int m){
/*
因为lazy1和lazy2标记只能同时存在一个,所以只需对其中一个操作即可
如果现有标记为lazy1,若进行取反,对lazy1异或即可,即原本全部覆盖成0的变成1,原本为1的变成0,不需对lazy2异或;
若进行覆盖操作,那么直接对lazy1修改。
如果现有标记为lazy2,若进行覆盖操作,那么lazy2直接变为0,;若进行取反操作,则对lazy2进行异或
*/
if(rt.lazy1!=-){
//01覆盖区间
ls.lazy1=rs.lazy1=rt.lazy1;
rs.lazy2=ls.lazy2=;
ls.num[rt.lazy1]=ls.lsum[rt.lazy1]=ls.rsum[rt.lazy1]=ls.msum[rt.lazy1]=m-m/;
ls.num[!rt.lazy1]=ls.lsum[!rt.lazy1]=ls.rsum[!rt.lazy1]=ls.msum[!rt.lazy1]=;
rs.num[rt.lazy1]=rs.lsum[rt.lazy1]=rs.rsum[rt.lazy1]=rs.msum[rt.lazy1]=m/;
rs.num[!rt.lazy1]=rs.lsum[!rt.lazy1]=rs.rsum[!rt.lazy1]=rs.msum[!rt.lazy1]=;
rt.lazy1=-;
}
else if(rt.lazy2){
//对区间取反
rt.lazy2=;
changexor(ls);
changexor(rs);
}
}
void build(int rt,int L,int R){
tree[rt].len=R-L+;
tree[rt].lazy1=-; //build时都忘记初始化了啊
tree[rt].lazy2=; //build时都忘记初始化了啊
if(L==R){
int v;
scanf("%d",&v);
tree[rt].lsum[v]=tree[rt].rsum[v]=tree[rt].msum[v]=;
tree[rt].lsum[!v]=tree[rt].rsum[!v]=tree[rt].msum[!v]=;
tree[rt].num[v]=;
tree[rt].num[!v]=;
tree[rt].lazy1=-;
return;
}
int mid=(L+R)>>;
build(lson);
build(rson);
pushUp(tree[rt],tree[rt<<],tree[rt<<|]);
} //进行操作01覆盖区间
void update(int rt,int L,int R,int l,int r,int c){
if(l<=L&&R<=r){
tree[rt].lazy2=; //之前的取反操作就无效了
tree[rt].num[c]=tree[rt].lsum[c]=tree[rt].rsum[c]=tree[rt].msum[c]=(R-L+);
tree[rt].num[!c]=tree[rt].lsum[!c]=tree[rt].rsum[!c]=tree[rt].msum[!c]=;
tree[rt].lazy1=c;
return;
}
pushDown(tree[rt],tree[rt<<],tree[rt<<|],R-L+);
int mid=(L+R)>>;
if(l<=mid)
update(lson,l,r,c);
if(r>mid)
update(rson,l,r,c);
pushUp(tree[rt],tree[rt<<],tree[rt<<|]);
}
//进行取反操作
void updatexor(int rt,int L,int R,int l,int r){
if(l<=L&&R<=r){
if(tree[rt].lazy1!=-)
tree[rt].lazy1^=; //如果之前有01标记,则要进行处理,对其异或,即取反
else
tree[rt].lazy2^=;
//只要将值互换一下即可
swap(tree[rt].num[],tree[rt].num[]);
swap(tree[rt].lsum[],tree[rt].lsum[]);
swap(tree[rt].rsum[],tree[rt].rsum[]);
swap(tree[rt].msum[],tree[rt].msum[]);
return;
}
pushDown(tree[rt],tree[rt<<],tree[rt<<|],R-L+);
int mid=(L+R)>>;
if(l<=mid)
updatexor(lson,l,r);
if(r>mid)
updatexor(rson,l,r);
pushUp(tree[rt],tree[rt<<],tree[rt<<|]);
}
//查询时,类型设为Node,进行节点合并,这样就方便好多
Node query(int rt,int L,int R,int l,int r){
if(l<=L&&R<=r){
return tree[rt];
}
pushDown(tree[rt],tree[rt<<],tree[rt<<|],R-L+);
int mid=(L+R)>>;
Node tmp,r1,r2;
if(r<=mid)
tmp=query(lson,l,r);
else if(l>mid)
tmp=query(rson,l,r);
else{
r1=query(lson,l,mid);
r2=query(rson,mid+,r);
tmp.len=r1.len+r2.len;
pushUp(tmp,r1,r2); //将节点r1和r2合并成tmp
}
return tmp;
} int main()
{
int op,a,b;
Node ans;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
build(,,n);
for(int i=;i<=m;i++){
scanf("%d%d%d",&op,&a,&b);
a++;b++;
if(op<=)
update(,,n,a,b,op);
else if(op==)
updatexor(,,n,a,b);
else{
ans=query(,,n,a,b);
if(op==)
printf("%d\n",ans.num[]);
else
printf("%d\n",ans.msum[]);
}
}
}
return ;
}
HDU 3397 Sequence operation (区间合并,操作比较多)的更多相关文章
- 【线段树】HDU 3397 Sequence operation 区间合并
操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters i ...
- HDU 3397 Sequence operation(线段树)
HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 0 a b [a.b]区间置为0 1 a b [a,b]区间置为1 2 a b [a,b]区间0变 ...
- HDU 3397 Sequence operation(区间合并 + 区间更新)
题目链接:pid=3397">http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给定n个数,由0,1构成.共同拥有5种操作. 每一个操 ...
- hdu 3397 Sequence operation 线段树 区间更新 区间合并
题意: 5种操作,所有数字都为0或1 0 a b:将[a,b]置0 1 a b:将[a,b]置1 2 a b:[a,b]中的0和1互换 3 a b:查询[a,b]中的1的数量 4 a b:查询[a,b ...
- hdu 3397 Sequence operation(很有意思的线段树题)
Sequence operation Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- HDU 3397 Sequence operation
题目:下列操作 Change operations:0 a b change all characters into '0's in [a , b]1 a b change all character ...
- hdu 3397 Sequence operation (线段树 区间合并 多重标记)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问 ...
- (简单) HDU 3397 Sequence operation,线段树+区间合并。
Problem Description lxhgww got a sequence contains n characters which are all '0's or '1's. We have ...
- hdu 3397 Sequence operation(线段树:区间更新)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给你一个长度为n的0,1序列,支持下列五种操作, 操作0(0 a b):将a到b这个区间的 ...
随机推荐
- 杭电2034——人见人爱A-B
#include <stdio.h> #include <algorithm> using namespace std; int main () { int a[110],b[ ...
- 正确编写Designated Initializer的几个原则
Designated Initializer(指定初始化器)在Objective-C里面是很重要的概念,但是在日常开发中我们往往会忽视它的重要性,以至于我们写出的代码具有潜藏的Bug,且不易发现.保证 ...
- <Linux下echo指令>
echo这个命令我们最常见的还是在shell脚本中的使用,if语句,for语句,case语句....这些都不是对echo命令的全面了解.下面还有很多其他echo的参数: 来自本人的日常生活,和对资料查 ...
- yum最常用的命令
yum是一个用于管理rpm包的后台程序,用python写成,可以非常方便的解决rpm的依赖关系.在建立好yum服务器后,yum客户端可以通过 http.ftp方式获得软件包,并使用方便的命令直接管理. ...
- GitHub for Windows离线安装的方法
这几天一直在尝试安装GitHub for windows ,安装程序是从https://windows.github.com/ 下载到的OneClick 部署程序,版本号为2.11.0.5.可能是因为 ...
- Asp.net MVC知识积累
一.知识积累 http://yuangang.cnblogs.com/ 跟蓝狐学mvc教程专题目录:http://www.lanhusoft.com/Article/169.html 依赖注入:htt ...
- perl中shift 和unshift 操作
##################################################################### unshift 和shift 对一个数组的开头进行操作(数组 ...
- OSGI容器与插件
插件必须符合osgi规范才能插到osgi容器中,osgi容器查看插件jar中MANIFEST.MF中osgi容器. 所谓插件----就是打包好的jar文件, 内部都封装好了一些功能
- Log.i()的用法
2011-04-16 09:44 17486人阅读 评论(4) 收藏 举报 androidlayoutbuttonstringencodingeclipse 在调试代码的时候我们需要查看调试信息,那我 ...
- MVC学习系列——HtmlHelper扩展
微软自带很多HtmlHelper: ActionLink - 链接到操作方法.BeginForm - 标记窗体的开头并链接到呈现该窗体的操作方法.CheckBox - 呈现复选框.DropDown ...