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这个区间的 ...
随机推荐
- 使用DbVisualizer 8 连接Oracle数据库
1. 网上下载一个驱动包ojdbc14.jar,放到oracle目录下:...\DbVisualizer-8.0.1\jdbc\oracle\ojdbc14.jar 2. 打开 DbVisualize ...
- linux中的namespace
本文将就namespace这个知识点,进行简单的归纳总结,力求通俗易通.在资料汇总的过程中,参考了许多网上的博客资料,在文章尾部给出相关链接. namespace,命名空间,从名字 ...
- 一款功能强大的iphone购物应用源码
一款功能强大的iphone购物应用源码,这款应用源码比较完整的,并且还支持信用卡支付服务等功能的,基本实现了我们常用的购物应用功能了,实现商品的基本展示功能,还具有完整的用户管理,以及完整的购物流程等 ...
- 转 XMLHttpRequest().readyState的五种状态详解
转 http://javathinker.blog.ccidnet.com/blog-htm-itemid-1262479-do-showone-type-blog-uid-36384.html 在& ...
- 打造自己的3D全景漫游
three.js 示例: 打造H5里的"3D全景漫游"秘籍 - 腾讯ISUX QQ物联星球计划 通过pano2vr直接将鱼眼全景图生成立体空间的六个面:也可通过Photos ...
- Ubuntu14.04忘记root密码的解决方法
电脑20多天没用忘记密码了,下面是在网上找到的一个解决办法,其它的和这个也大概相同.因为其中有些缺漏,没能给我解决问题.通过分析最终问题还是解决了,现解决方案的关键点记录一下.希望能方便到其它人. 1 ...
- python 快速入门
根据以下几个步骤来快速了解一下python,目标是可以利用python来处理一些简易的问题或者写一些工具. 1.编写Hello world 2.学习 if,while,for 的语法 3.学习该语 ...
- 2013-07-26 IT 要闻速记快想
### ========================= ###传Google正在内测供用户买卖技能的电商平台Helpout,最早于下月上线该服务将依托Google强大的云服务和搜索能力,以实时视频 ...
- EcilpsePHP studio 3.0 运行(run)环境配置
EcilpsePHP studio 3.0的界面与 MyEclipse操作界面基本一样,熟悉后者的对于EcilpsePHP studio 的使用学习就不会太难了. 安装好EPP后,新建项目--> ...
- Translation001——android
请尊重原创,转载请注明出处: Author:KillerLegend Link:http://www.cnblogs.com/killerlegend/ BEGIN****************** ...