费了我一天半的时间,到处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 (区间合并,操作比较多)的更多相关文章

  1. 【线段树】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 ...

  2. 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变 ...

  3. HDU 3397 Sequence operation(区间合并 + 区间更新)

    题目链接:pid=3397">http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给定n个数,由0,1构成.共同拥有5种操作. 每一个操 ...

  4. 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 ...

  5. hdu 3397 Sequence operation(很有意思的线段树题)

    Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  6. HDU 3397 Sequence operation

    题目:下列操作 Change operations:0 a b change all characters into '0's in [a , b]1 a b change all character ...

  7. hdu 3397 Sequence operation (线段树 区间合并 多重标记)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问 ...

  8. (简单) HDU 3397 Sequence operation,线段树+区间合并。

    Problem Description lxhgww got a sequence contains n characters which are all '0's or '1's. We have ...

  9. hdu 3397 Sequence operation(线段树:区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给你一个长度为n的0,1序列,支持下列五种操作, 操作0(0 a b):将a到b这个区间的 ...

随机推荐

  1. 杭电ACM2091--空心三角形

    http://acm.hdu.edu.cn/showproblem.php?pid=2091 scanf 和 printf的输入输出功能并不强大.有时候我们需要清空输入输出流,所以一定切记getcha ...

  2. 洛谷 P3399 丝绸之路

    题目背景 张骞于公元前138年曾历尽艰险出使过西域.加强了汉朝与西域各国的友好往来.从那以后,一队队骆驼商队在这漫长的商贸大道上行进,他们越过崇山峻岭,将中国的先进技术带向中亚.西亚和欧洲,将那里的香 ...

  3. 素数个数统计——Eratosthenes筛法 [LeetCode 204]

    1- 问题描述 Count the number of prime numbers less than a non-negative number, n 2- 算法思想 给出要筛数值的范围 $n$,找 ...

  4. SQL语句执行顺寻

    SQL语句执行的时候是有一定顺序的.理解这个顺序对SQL的使用和学习有很大的帮助. 1.from 先选择一个表,或者说源头,构成一个结果集. 2.where 然后用where对结果集进行筛选.筛选出需 ...

  5. 《Apache之虚拟主机的配置》——RHEL6.3

    1.安装httpd软件包: Yum install httpd 2.启动apache服务: [root@redhat Desktop]# /etc/init.d/httpd start Startin ...

  6. LVS-HA

    heartbeat 监听在udp的694的端口   LRM:本地资源管理器 CRM:资源管理器 RA:资源代理(脚本) heartbeat legacy : heartbeat 传统类型的资源代理,通 ...

  7. WCF 服务的ABC之地址(五)

    地址 Address 在WCF中,每个服务都有一个唯一的地址(Address). 地址包含两个重要的元素:服务位置及传输协议. 服务位置包含目标机器名.站点.通信端口.管道(或队列),以及一个可选的特 ...

  8. 看部电影,透透彻彻理解IoC(你没有理由再迷惑!)

    引述:IoC(控制反转:Inverse of Control)是Spring容器的内核,AOP.声明式事务等功能在此基础上开花结果.但是IoC这个重要的概念却比较晦涩隐讳,不容易让人望文生义,这不能不 ...

  9. CSS3制作立体导航

    <ul class="nav"> <li><a href="">首页</a></li> <li ...

  10. TortoiseGit 安装和使用的图文教程

    TortoiseGit.SourceTree都是Windows下不错的Git客户端工具,下面介绍一下TortoiseGit安装和使用的方法. 安装TortoiseGit并使用它需要两个软件:Torto ...