1858: [Scoi2010]序列操作

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1961  Solved: 991
[Submit][Status][Discuss]

Description

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0 3 a b 询问[a, b]区间内总共有多少个1 4 a b 询问[a, b]区间内最多有多少个连续的1 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

Input

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作="" <="" div="">

Output

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

Sample Input

10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9

Sample Output

5
2
6
5

HINT

对于30%的数据,1<=n, m<=1000
对于100%的数据,1<=n, m<=100000

Source

Day2

Solution

线段树裸题,但是...

维护各种量:左/右端点,区间大小,覆盖标记,翻转标记,1/0的数量,连续出现次数,左右段的量,是否完全覆盖....

标记之间各种相互作用...比如 覆盖标记时清零翻转标记...

向上更新值的时候,不太同于以往..分类讨论左右段来合并..

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100010
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
int n,m;
struct Treenode{int tag,rev,l,r,size,sum[],L[],R[],num[],da;}tree[maxn<<];
inline Treenode merge(Treenode a,Treenode b)
{
Treenode re;
re.l=a.l; re.r=b.r; re.size=re.r-re.l+; re.rev=; re.tag=-;
re.L[]=a.L[]; re.L[]=a.L[]; re.R[]=b.R[]; re.R[]=b.R[];
re.num[]=max(a.num[],b.num[]); re.num[]=max(a.num[],b.num[]);
re.num[]=max(re.num[],a.R[]+b.L[]); re.num[]=max(re.num[],a.R[]+b.L[]);
re.sum[]=a.sum[]+b.sum[]; re.sum[]=a.sum[]+b.sum[];
if(a.da==) re.L[]=a.num[]+b.L[]; else if(a.da==) re.L[]=a.num[]+b.L[];
if(b.da==) re.R[]=b.num[]+a.R[]; else if(b.da==) re.R[]=b.num[]+a.R[];
if(a.da==b.da) re.da=a.da; else re.da=-;
return re;
}
inline void update(int now)
{
tree[now]=merge(tree[now<<],tree[now<<|]);
}
inline void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;
tree[k].tag=-; tree[k].size=r-l+;
if(l==r)
{
scanf("%d",&tree[k].da);
if(tree[k].da)
{tree[k].L[]=tree[k].R[]=tree[k].num[]=tree[k].sum[]=;}
else
{tree[k].L[]=tree[k].R[]=tree[k].num[]=tree[k].sum[]=;}
return;
}
int mid=(l+r)>>;
build(k<<,l,mid);build(k<<|,mid+,r);
update(k);
}
inline void paintrev(int now)
{
swap(tree[now].L[],tree[now].L[]);
swap(tree[now].R[],tree[now].R[]);
swap(tree[now].num[],tree[now].num[]);
swap(tree[now].sum[],tree[now].sum[]);
if (tree[now].da!=-) tree[now].da^=;
}
inline void painttag(int now,int D)
{
tree[now].rev=;
if (D!=)
{
tree[now].sum[]=tree[now].L[]=tree[now].R[]=tree[now].num[]=,
tree[now].sum[]=tree[now].L[]=tree[now].R[]=tree[now].num[]=tree[now].size;
}
else
{
tree[now].sum[]=tree[now].L[]=tree[now].R[]=tree[now].num[]=tree[now].size,
tree[now].sum[]=tree[now].L[]=tree[now].R[]=tree[now].num[]=;
}
tree[now].da=D;
}
inline void pushdown(int now)
{
if (tree[now].l==tree[now].r) return;
if (tree[now].tag!=-)
{
tree[now<<].tag=tree[now<<|].tag=tree[now].tag;
painttag(now<<,tree[now].tag); painttag(now<<|,tree[now].tag); tree[now].tag=-;
}
if (tree[now].rev)
{
tree[now<<].rev^=; tree[now<<|].rev^=;
paintrev(now<<); paintrev(now<<|); tree[now].rev=;
}
}
inline void change(int now,int L,int R,int D)
{
pushdown(now);
if(tree[now].l==L && tree[now].r==R) {painttag(now,D);tree[now].tag=D;return;}
int mid=(tree[now].l+tree[now].r)>>;
if(mid>=R) change(now<<,L,R,D);
else if(mid<L) change(now<<|,L,R,D);
else change(now<<,L,mid,D),change(now<<|,mid+,R,D);
update(now);
}
inline void reserv(int now,int L,int R)
{
pushdown(now);
if(tree[now].l==L && tree[now].r==R) {paintrev(now);tree[now].rev^=;return;}
int mid=(tree[now].l+tree[now].r)>>;
if(mid>=R) reserv(now<<,L,R);
else if(mid<L) reserv(now<<|,L,R);
else reserv(now<<,L,mid),reserv(now<<|,mid+,R);
update(now);
}
inline int asksum(int now,int L,int R)
{
pushdown(now);
if(tree[now].l==L && tree[now].r==R) return tree[now].sum[];
int mid=(tree[now].l+tree[now].r)>>;
if(mid>=R) return asksum(now<<,L,R);
else if(mid<L) return asksum(now<<|,L,R);
else return asksum(now<<,L,mid)+asksum(now<<|,mid+,R);
update(now);
}
inline Treenode asknum(int now,int L,int R)
{
pushdown(now);
if (L==tree[now].l && R==tree[now].r) return tree[now];
int mid=(tree[now].l+tree[now].r)>>;
if (mid>=R) return asknum(now<<,L,R);
else if(mid<L)return asknum(now<<|,L,R);
else return merge(asknum(now<<,L,mid),asknum(now<<|,mid+,R));
}
int main()
{
n=read(),m=read();build(,,n);
while (m--)
{
int opt=read(),l=read(),r=read(); l++;r++;
switch (opt)
{
case : change(,l,r,);break;
case : change(,l,r,);break;
case : reserv(,l,r);break;
case : printf("%d\n",asksum(,l,r));break;
case : printf("%d\n",asknum(,l,r).num[]);break;
}
}
return ;
}

手一点误就调好久,巨恶心..  自己讨论的不够好..还重敲了一遍....至于压代码?Char哥比我短80行..

【BZOJ-1858】序列操作 线段树的更多相关文章

  1. bzoj 2962 序列操作——线段树(卷积?)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 如果 _,_,_,…… 变成了 (_+k),(_+k),(_+k),…… ,计算就是在 ...

  2. bzoj 2962 序列操作 —— 线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 维护 sum[i] 表示选 i 个的乘积和,合并两个子树就枚举两边选多少,乘起来即可: ...

  3. bzoj 1858 序列操作

    bzoj 1858 序列操作 带有随机多个区间单值覆盖的区间操作题,可考虑用珂朵莉树解决. #include<bits/stdc++.h> using namespace std; #de ...

  4. 【题解】P4247 [清华集训]序列操作(线段树修改DP)

    [题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...

  5. BZOJ 1858: [Scoi2010]序列操作( 线段树 )

    略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...

  6. 【BZOJ-2962】序列操作 线段树 + 区间卷积

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 678  Solved: 246[Submit][Status][Discuss] ...

  7. 【bzoj1858】[Scoi2010]序列操作 线段树区间合并

    题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...

  8. 【BZOJ2962】序列操作 线段树

    [BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...

  9. bzoj1858[Scoi2010]序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 3079  Solved: 1475[Submit][Statu ...

随机推荐

  1. ubuntu12.04禁止单用户本地无密码root登录

    1)grub-mkpasswd-pbkdf2 拿到类似grub.pbkdf2.sha512.10000.C093FE6825CDCC2F84934ABC406445E92EE098733C60E6D1 ...

  2. SQL 按特定字段值排序

    SQL 按特定字段值排序的代码,有需要的朋友可以参考下. id, name shandong01 name1 shandong02 name2 shandong03 name3 beijing01 n ...

  3. css中如何设置字体

    来自百度的回答: 建议使用font-family: "Microsoft YaHei";支持UTF-8和GB2312字符集. 不生效的3种情况:1.当此属性定义的是全局样式时,对于 ...

  4. AngularJS中的身份验证

    欢迎大家指导与讨论 : )  一.  身份验证的意义  首先呢,网络应用的身份验证的意图在于:保护网站中的重要资源.基于某些原因这些资源并不能公开,比如付费资源(交过钱的用户才能上的网络课程),或者一 ...

  5. [转]PHP 下使用 ZeroMQ 和 protobuf

    FROM : http://www.68idc.cn/help/makewebs/php/20150118175432.html 前言 这个记录总的来说分两部分: 搭建环境. 简单使用教程. 搭建环境 ...

  6. quartz.net 项目无法加载的问题

    最近尝试试用一下quartz.net 做任务调度用. 下载了源代码后打开解决方案发现项目无法加载.错误如下 未找到导入的项目“C:\Users\****\Desktop\Quartz.NET-2.1. ...

  7. WPF中的数据验证

    数据验证 WPF的Binding使得数据能够在数据源和目标之间流通,在数据流通的中间,便能够对数据做一些处理. 数据转换和数据验证便是在数据从源到目标 or 从目标到源 的时候对数据的验证和转换. V ...

  8. Qt 学习笔记 TreeWidget 增删改

    在窗体上放一个TreeWidget控件和四个PushButton加一个Horizontal Spacer 布局如图 给树添加元素节点的方法和实现 .h文件 QTreeWidgetItem * AddT ...

  9. Java:反射

    初识Java反射机制: 从上面的描述可以看出Java的反射机制使得Java语言可以在运行时去认识在编译时并不了解的类/对象的信息,并且能够调用相应的方法或修改属性的值.Java反射机制的核心就是允许在 ...

  10. 从idea上通过路径去导入项目

    这里我用git来演示导入. 首先确定你要导入项目的路径.(我这里用码云路径图片做演示) 1.选择 2.填写