[SCOI2010]序列操作 线段树
题解:
在考场上打的这道题,出人意料的很快就打完了?!
直接用线段树,维护几个东西:
1,lazy标记 : 表示区间赋值
2,mark标记:表示区间翻转
3,l1:前缀最长连续的1的子段长度
4,l0:前缀最长连续的0的子段长度
5,m0:区间内最长的全为0的子段的长度
6,r0:后缀最长连续的0的子段长度
7,r1:后缀最长连续的1的子段长度
8,m1:区间内最长的全为1的子段的长度
9,sum :区间和
维护起来比较繁琐,细节较多,但是都不难,是可以自己想出来的。
这里提一个可以忽略标记处理顺序的小技巧:
因为lazy标记是可以覆盖mark标记的,因此一个节点在得到lazy标记时,清空mark标记。
因为mark标记可以看做是直接对lazy标记进行翻转,因此如果一个节点已经有lazy标记,那么在打上mark标记时,可以选择不得到mark标记,而是直接对lazy标记进行修改。
因此不论是什么情况,mark标记和lazy标记都不会同时存在,也就不会有处理的先后顺序问题了。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 101000
#define ac 800000
#define LL long long
int n, m, ans;
int s[AC];
int sum[ac], lazy[ac], l1[ac], r1[ac], l0[ac], r0[ac], m1[ac], m0[ac], l[ac], r[ac];
bool mark[ac]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline void upmin(int &a, int b)
{
if(b < a) a = b;
} inline void upmax(int &a, int b)
{
if(b > a) a = b;
} inline int Max(int a, int b)
{
if(a > b) return a;
else return b;
} void update(int x)//更新信息
{
int ll = x * , rr = x * + ;
m1[x] = Max(m1[ll], m1[rr]);
upmax(m1[x], r1[ll] + l1[rr]);
m0[x] = Max(m0[ll], m0[rr]);
upmax(m0[x], r0[ll] + l0[rr]);
if(sum[rr] == r[rr] - l[rr] + ) r1[x] = sum[rr] + r1[ll];
else r1[x] = r1[rr];
if(!sum[rr]) r0[x] = r[rr] - l[rr] + + r0[ll];
else r0[x] = r0[rr];
if(sum[ll] == r[ll] - l[ll] + ) l1[x] = sum[ll] + l1[rr];
else l1[x] = l1[ll];
if(!sum[ll]) l0[x] = r[ll] - l[ll] + + l0[rr];
else l0[x] = l0[ll];
sum[x] = sum[ll] + sum[rr];
} void getlazy(int x, int go)
{
if(go == )
{
lazy[x] = , sum[x] = ;
l1[x] = r1[x] = m1[x] = ;
l0[x] = r0[x] = m0[x] = r[x] - l[x] + ;
}
else if(go == )
{
lazy[x] = ;
sum[x] = r[x] - l[x] + ;
l1[x] = r1[x] = m1[x] = sum[x];
l0[x] = r0[x] = m0[x] = ;
}
mark[x] = ;//区间赋值可以抵消区间反转
} void getmark(int x)
{
mark[x] ^= ;//翻转翻转标记
if(lazy[x]) getlazy(x, lazy[x] % + );
else
{
sum[x] = r[x] - l[x] + - sum[x];
swap(l1[x], l0[x]), swap(r1[x], r0[x]);
swap(m1[x], m0[x]);
}
} void pushdown(int x)//下传标记
{
if(lazy[x])
{
int ll = x * , rr = ll + ;
if(lazy[x] == )//change to 0
getlazy(ll, ), getlazy(rr, );
else//change to 1
getlazy(ll, ), getlazy(rr, );
lazy[x] = ;
}
if(mark[x])
{
int ll = x * , rr = ll + ;
getmark(ll), getmark(rr);
mark[x] = ;
}
} void change(int x, int ll, int rr, int go)//区间修改
{
pushdown(x);
if(l[x] == ll && r[x] == rr)
{
if(go <= ) getlazy(x, go);
else getmark(x);
return;
}
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) change(x * , ll, rr, go);
else if(ll > mid) change(x * + , ll, rr, go);
else
{
change(x * , ll, mid, go);
change(x * + , mid + , rr, go);
}
update(x);
} void getsum(int x, int ll, int rr)
{
pushdown(x);
if(l[x] == ll && r[x] == rr)
{
ans += sum[x];
return ;
}
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) getsum(x * , ll, rr);
else if(ll > mid) getsum(x * + , ll, rr);
else
{
getsum(x * , ll, mid);
getsum(x * + , mid + , rr);
}
} void find(int x, int ll, int rr)//询问连续1的长度
{
pushdown(x);
if(l[x] == ll && r[x] == rr)
{
upmax(ans, m1[x]);
return ;
}
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) find(x * , ll, rr);
else if(ll > mid) find(x * + , ll, rr);
else
{
int tmp = min(mid - ll + , r1[x * ]) + min(rr - mid, l1[x * + ]);
find(x * , ll, mid);
find(x * + , mid + , rr);
upmax(ans, tmp);
}
} void build(int x, int ll ,int rr)
{
l[x] = ll, r[x] = rr;
if(l[x] == r[x])
{
sum[x] = l1[x] = r1[x] = m1[x] = s[l[x]];
if(!sum[x]) l0[x] = r0[x] = m0[x] = ;
return ;
}
int mid = (ll + rr) >> ;
build(x * , ll, mid);
build(x * + , mid + , rr);
update(x);
} void pre()
{
n = read(), m = read();
for(R i = ; i <= n; i ++) s[i] = read();
} void work()
{
int opt, a, b;
for(R i = ; i <= m; i ++)
{
// printf("!!!%d\n", i);
opt = read(), a = read() + , b = read() + ;
if(!opt) change(, a, b, );
else if(opt == ) change(, a, b, );
else if(opt == ) change(, a, b, );
else if(opt == )
{
ans = ;
getsum(, a, b);
printf("%d\n", ans);
}
else if(opt == )
{
ans = ;
find(, a, b);
printf("%d\n", ans);
}
}
} int main()
{
//freopen("operation.in", "r", stdin);
// freopen("operation.out", "w", stdout);
pre();
build(, , n);
work();
//fclose(stdin);
//fclose(stdout);
return ;
}
[SCOI2010]序列操作 线段树的更多相关文章
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- bzoj1858[Scoi2010]序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3079 Solved: 1475[Submit][Statu ...
- 【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 ...
- bzoj1858 [Scoi2010]序列操作——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1858 线段树...调了一个上午...(后面带 // 的都是改出来的) lazy 标记的下放好 ...
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- 【BZOJ-1858】序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ...
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ...
随机推荐
- MAthJax入门教程(五分钟上手)
最近在研究,在页面中显示一些数学公式.搞得我很头疼. 据说MathJax会统一这已领域.所以去学了学.网上教程特别多.繁杂. 说的清楚的特别少. 我是这么跑通的,: 1.在官网下载代码地址为:http ...
- linux wdcp3 上传大文件 服务器i/o错误
在一次上传大文件时 提示 服务器i/o错误 找了些方法都没有解决 最后发现 wdcp3 面板 默认安装时 web服务器引擎是 nginx + apache 共用 而且 nginx 默认并没与安装 ...
- 《python编程从入门到实践》第六章笔记
1.字典 字典:一系列键-值对,每一个键都与每一个值相关联.与键相关联的值可以是数字.字符串.列表和字典. 最简单的字典只有一个键值对. eg: alien = {'color':'green','p ...
- 怎么修复网站漏洞之metinfo远程SQL注入漏洞修补
2018年11月23日SINE网站安全检测平台,检测到MetInfo最新版本爆出高危漏洞,危害性较大,影响目前MetInfo 5.3版本到最新的 MetInfo 6.1.3版本,该网站漏洞产生的主要原 ...
- MFC接收ShellExecute多个参数
在应用程序开发过程中,我们经常需要带参数启动另一个执行程序,如何传递多个参数,如何解析多个参数呢? 传参数 传递参数可使用ShellExecute函数,示例如下: ShellExecute(NUL ...
- 2844: albus就是要第一个出场
2844: albus就是要第一个出场 链接 分析: 和HDU3949差不多互逆,这里需要加上相同的数. 结论:所有数任意异或,构成的数出现一样的次数,次数为$2^{n-cnt}$,cnt为线性基的大 ...
- VS2010安装MVC3出错
开始已经在电脑上安装了VS2010以及SP1,还装了MVC4的相关升级包.最后项目中又要用MVC3,然后又去安装MVC3的安装包,但是在安装的过程就出现了问题.一直安装不成功,最后在 ...
- 如何修改Github上提交的错误用户地址和姓名
Changing author info https://help.github.com/articles/changing-author-info/ To change the name an ...
- VIN码识别:助力汽车后市场转型升级
随着中国汽车市场的成熟,汽车后市场发展迅速,呈“井喷”式增长.据最新数据统计,2015年,中国汽车后市场产值突破8000亿规模,到2018年有望突破万亿. 所谓汽车后市场是指汽车销售以后,围绕汽车使用 ...
- python第三天(list,元组,dictionary)
1.list 列表 列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现. 列表的数据项不需要具有相同的类型 创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可.如下 ...