bzoj1858 [Scoi2010]序列操作——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1858
线段树...调了一个上午...(后面带 // 的都是改出来的)
lazy 标记的下放好麻烦,还得考虑赋值和取反的先后顺序什么的...
因为在取反时把赋值标记 swap 了,所以下放的时候先判断取反再判断赋值...
而且WA了一上午的原因竟然是一开始不慎把取反以为成翻转了,后来没改干净...那个 rev 的名字啊...
总之没有太改变自己最初的想法、改了些细节就A了还是很高兴的!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=1e5+;
int n,m,op,a,b,c[maxn];
struct N{
int sum,z[],y[],m[];
int lz[],rev,len;
}t[maxn<<];
int rd()
{
int ret=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return ret;
}
void pushup(int x)
{
int ls=(x<<),rs=(x<<|);
t[x].sum=t[ls].sum+t[rs].sum;
for(int i=;i<=;i++)
{
t[x].z[i]=t[ls].z[i]+(t[ls].z[i]==t[ls].len?t[rs].z[i]:);
t[x].y[i]=t[rs].y[i]+(t[rs].y[i]==t[rs].len?t[ls].y[i]:);
// t[x].m[i]=max(max(t[x].z[i],t[x].y[i]),t[ls].y[i]+t[rs].z[i]);//
t[x].m[i]=max(max(t[ls].m[i],t[rs].m[i]),t[ls].y[i]+t[rs].z[i]);//
}
}
void upt(int x,int val)//赋值
{
t[x].lz[val]=;
t[x].lz[!val]=; t[x].rev=;//!
t[x].sum=t[x].len*val;
t[x].z[val]=t[x].y[val]=t[x].m[val]=t[x].len;
t[x].z[!val]=t[x].y[!val]=t[x].m[!val]=;
}
void re(int x)//取反
{
swap(t[x].z[],t[x].z[]); swap(t[x].y[],t[x].y[]);//!!!
swap(t[x].m[],t[x].m[]);
t[x].sum=t[x].len-t[x].sum; t[x].rev^=;
swap(t[x].lz[],t[x].lz[]);//!
}
void pushdown(int x)
{
// if(t[x].len==1)return;//
int ls=(x<<),rs=(x<<|);
if(t[x].rev)t[x].rev^=,re(ls),re(rs);
for(int v=;v<=;v++)
if(t[x].lz[v])t[x].lz[v]=,upt(ls,v),upt(rs,v);//顺序
}
void build(int x,int l,int r)
{
t[x].len=r-l+;
if(l==r)
{
t[x].z[c[l]]=t[x].y[c[l]]=t[x].m[c[l]]=;
t[x].sum=c[l]; //
return;
}
int mid=((l+r)>>);
build(x<<,l,mid); build(x<<|,mid+,r);
pushup(x);
}
void update(int x,int l,int r,int L,int R,int val)
{
if(l>=L&&r<=R)
{
upt(x,val);return;
}
pushdown(x);
int mid=((l+r)>>);
if(mid>=L)update(x<<,l,mid,L,R,val);
if(mid<R)update(x<<|,mid+,r,L,R,val);
pushup(x);
}
void rever(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)
{
re(x);return;
}
int mid=((l+r)>>);
pushdown(x);
if(mid>=L)rever(x<<,l,mid,L,R);
if(mid<R)rever(x<<|,mid+,r,L,R);
pushup(x);
}
int query(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)return t[x].sum;
int mid=((l+r)>>),ret=;
pushdown(x);
if(mid>=L)ret+=query(x<<,l,mid,L,R);
if(mid<R)ret+=query(x<<|,mid+,r,L,R);
return ret;
}
int ask(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)return t[x].m[];
pushdown(x);//
int mid=((l+r)>>);
if(mid>=R)return ask(x<<,l,mid,L,R);
if(mid<L)return ask(x<<|,mid+,r,L,R);
int ret=;
ret=max(ask(x<<,l,mid,L,R),ask(x<<|,mid+,r,L,R));
ret=max(ret,min(t[x<<].y[],mid-L+)+min(t[x<<|].z[],R-mid));
return ret;
}
int main()
{
n=rd();m=rd();
for(int i=;i<=n;i++)c[i]=rd();
build(,,n);
while(m--)
{
op=rd(); a=rd()+; b=rd()+;
if(op==||op==)update(,,n,a,b,op);
if(op==)rever(,,n,a,b);
if(op==)printf("%d\n",query(,,n,a,b));
if(op==)printf("%d\n",ask(,,n,a,b));
}
return ;
}
bzoj1858 [Scoi2010]序列操作——线段树的更多相关文章
- bzoj1858[Scoi2010]序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3079 Solved: 1475[Submit][Statu ...
- 【BZOJ-1858】序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- Luogu P2572 [SCOI2010]序列操作 线段树。。
咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...
- 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树
正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...
- [SCOI2010]序列操作 线段树
---题面--- 题解: 在考场上打的这道题,出人意料的很快就打完了?! 直接用线段树,维护几个东西: 1,lazy标记 : 表示区间赋值 2,mark标记:表示区间翻转 3,l1:前缀最长连续的1的 ...
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- BZOJ1858 [Scoi2010]序列操作(线段树)
题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...
随机推荐
- 病毒的侵扰和再侵扰两道AC自动机的应用
HDU2896 病毒的侵扰 http://vjudge.net/problem/viewProblem.action?id=16404 题目大意: 记录每个病毒的编号,并给出一些网站的源码,分别输出网 ...
- Codeforces Round #296 (Div. 2) C. Glass Carving [ set+multiset ]
传送门 C. Glass Carving time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- windows 下安装Apache httpd 只需三步
1.下载 Apache 官网地址:http://httpd.apache.org/docs/current/platform/windows.html#down 找到这个, 看到这几个选项: Apac ...
- C. Nearest vectors--cf598C(极角排序)
http://codeforces.com/problemset/problem/598/C 题目大意: 给你你个向量 向量的起点都是从(0,0)开始的 求哪个角最小 输出这两个向量 这是第一 ...
- asterisk 通道变量
${ACCOUNTCODE}: 用户计费帐号 sip.conf 里的 account=XXXX ${ANSWEREDTIME}: 通话时长(秒) ${BLINDTRANSFER}: 通道是否为转接类型 ...
- git服务端安装
Windows平台下Git服务器搭建 第一步:下载Java,下载地址:http://www.java.com/zh_CN/ 注意要下载是完整的JDK(其中有jre) 第二步:安装Java.安装步骤不 ...
- hdoj 3351 Seinfeld 【栈的简单应用】
Seinfeld Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- Win7 丢失MSVCR110.DLL的解决办法
1 从下面的网站下载dll文件 http://www.ddooo.com/softdown/27034.htm 2 把该文件放到C:\Windows\SysWOW64目录下(64位系统)或者C:\ ...
- Dubbo应用启动与停止脚本,超具体解析
本周刚好研究了一下dubbo的启动脚本,所以在官网的启动脚本和公司内部的启动脚本做了一个整理,弄了一份比較通过的Dubbo应用启动和停止脚本. 以下的脚本仅仅应用于配置分离的应用.什 ...
- ASP.net MVC+ViewData VS ViewBag
在使用MVC框架的过程中,往界面传值,我们使用的ViewData.如ITOO部分代码图解: 当然除了ViewData,我们还能够使用同卵兄弟(ViewBag)来完毕相同的功能,详情 ...