Problem 1007 幸运数 线段树成段更新
题目链接:
题目
Problem 1007 幸运数
Time Limit: 2000 mSec
Memory Limit : 131072 KB
问题描述
皮特的幸运数是2和5。只由幸运数字2和5组成的数列,称为幸运数列。对于幸运数列,有两种操作。
1、switch i j
表示数列从第i个数到第j个数中,所有的2改成5,所有的5改成2.例如幸运数列25525,执行switch 2 4操作,则数列变成22255
2、count
表示要求输出当前幸运数列的最长不下降子序列(即子序列中后面的数都不小于前面的数)的长度。例如幸运数列252255,其中222,555,2555是它的不下降子序列,而2525不是,可以看出,最长不下降子序列是22255,长度为5。
现在给出一个长度为n的幸运数列,再依次给出m个操作,对于每个count操作,输出当前幸运数列的最长不下降子序列的长度。
输入
输入包含多组数据。(数据不超过10组)
每组数据的第一行有两个整数n,m(n,m<=100000),分别表示数列的长度和操作个数。
接下来一行,有一个长度为n的只由2和5构成的数列。
接下来m行,每行一个操作,是count或者switch i j,含义如题所述
输出
对于每组数据的每个count操作,都输出一行,包含一个整数,表示当前幸运数列的最长不下降子序列的长度。
样例
input
2 3
25
count
switch 1 2
count
3 5
525
count
switch 1 1
count
switch 1 3
count
output
2
1
2
3
2
题解
可以用线段树跑成段更新。
每个节点维护四个变量,分别表示子序列"22","25","52","55"的长度
在2,5对换的时候,只要交换"22"和"55";"25"和"52"。
需要懒惰标记。(感觉懒惰标记写搓了。orz,后面学一下)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson (o<<1)
#define rson ((o<<1)|1)
#define M L+(R-L)/2
using namespace std;
const int maxn=101010;
int sumv[maxn<<2][4],setv[maxn<<2];
int n,m;
char str[maxn];
void pushdown(int o,int L,int R){
if(setv[o]>0){
swap(sumv[o][1],sumv[o][2]);
swap(sumv[o][0],sumv[o][3]);
if(L<R){
setv[lson]^=1; setv[rson]^=1;
}
setv[o]=0;
}
}
void maintain(int o,int L,int R){
if(L==R){
pushdown(o,L,R);
}else{
pushdown(lson,L,M);
pushdown(rson,M+1,R);
sumv[o][0]=sumv[lson][0]+sumv[rson][0];
sumv[o][3]=sumv[lson][3]+sumv[rson][3];
sumv[o][1]=max(sumv[lson][0]+sumv[rson][3],sumv[lson][1]+sumv[rson][3]);
sumv[o][1]=max(sumv[o][1],sumv[lson][0]+sumv[rson][1]);
sumv[o][2]=max(sumv[lson][3]+sumv[rson][0],sumv[lson][2]+sumv[rson][0]);
sumv[o][2]=max(sumv[o][2],sumv[lson][3]+sumv[rson][2]);
}
}
int ql,qr;
void update(int o,int L,int R){
if(ql<=L&&R<=qr){
setv[o]^=1;
pushdown(o,L,R);
}else{
pushdown(o,L,R);
if(ql<=M) update(lson,L,M);
if(qr>M) update(rson,M+1,R);
}
maintain(o,L,R);
}
void build(int o,int L,int R){
if(L==R){
memset(sumv[o],0,sizeof(sumv[o]));
if(str[L]=='2') sumv[o][0]=1;
else sumv[o][3]=1;
}else{
build(lson,L,M);
build(rson,M+1,R);
}
maintain(o,L,R);
}
void init(){
memset(setv,0,sizeof(setv));
}
int main(){
while(scanf("%d%d",&n,&m)==2){
init();
scanf("%s",str+1);
build(1,1,n);
char cmd[22];
while(m--){
scanf("%s",cmd);
if(cmd[0]=='c'){
printf("%d\n",max(sumv[1][0],max(sumv[1][1],sumv[1][3])));
}else{
scanf("%d%d",&ql,&qr);
update(1,1,n);
}
}
}
return 0;
}
改进版本:(看起来爽多了)
打标记的位置其实已经更新完毕了,打标记知识告诉后代要更新啦。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson (o<<1)
#define rson ((o<<1)|1)
#define M L+(R-L)/2
using namespace std;
const int maxn = 101010;
int sumv[maxn << 2][4], setv[maxn << 2];
int n, m;
char str[maxn];
void pushdown(int o, int L, int R) {
if (setv[o]>0&&L<R) {
swap(sumv[lson][1], sumv[lson][2]); swap(sumv[lson][0], sumv[lson][3]);
swap(sumv[rson][1], sumv[rson][2]); swap(sumv[rson][0], sumv[rson][3]);
setv[lson] ^= 1; setv[rson] ^= 1;
setv[o] = 0;
}
}
void maintain(int o, int L, int R) {
sumv[o][0] = sumv[lson][0] + sumv[rson][0];
sumv[o][3] = sumv[lson][3] + sumv[rson][3];
sumv[o][1] = max(sumv[lson][0] + sumv[rson][3], sumv[lson][1] + sumv[rson][3]);
sumv[o][1] = max(sumv[o][1], sumv[lson][0] + sumv[rson][1]);
sumv[o][2] = max(sumv[lson][3] + sumv[rson][0], sumv[lson][2] + sumv[rson][0]);
sumv[o][2] = max(sumv[o][2], sumv[lson][3] + sumv[rson][2]);
}
int ql, qr;
void update(int o, int L, int R) {
if (ql <= L&&R <= qr) {
setv[o] ^= 1;
swap(sumv[o][1], sumv[o][2]);
swap(sumv[o][0], sumv[o][3]);
}
else {
pushdown(o, L, R);
if (ql <= M) update(lson, L, M);
if (qr>M) update(rson, M + 1, R);
maintain(o, L, R);
}
}
void build(int o, int L, int R) {
if (L == R) {
memset(sumv[o], 0, sizeof(sumv[o]));
if (str[L] == '2') sumv[o][0] = 1;
else sumv[o][3] = 1;
}
else {
build(lson, L, M);
build(rson, M + 1, R);
maintain(o, L, R);
}
}
void init() {
memset(setv, 0, sizeof(setv));
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
init();
scanf("%s", str + 1);
build(1, 1, n);
char cmd[22];
while (m--) {
scanf("%s", cmd);
if (cmd[0] == 'c') {
printf("%d\n", max(sumv[1][0], max(sumv[1][1], sumv[1][3])));
}
else {
scanf("%d%d", &ql, &qr);
update(1, 1, n);
}
}
}
return 0;
}
Problem 1007 幸运数 线段树成段更新的更多相关文章
- poj 3468 A Simple Problem with Integers 【线段树-成段更新】
题目:id=3468" target="_blank">poj 3468 A Simple Problem with Integers 题意:给出n个数.两种操作 ...
- POJ 3468:A Simple Problem with Integers(线段树[成段更新])
题意:N个数Q次操作.一共两种操作:Q l r :询问[l,r]这个区间里的数字和,C l r c: [l,r]区间里的每个数都加上c.1 ≤ N,Q ≤ 100000. 方法:线段树的成段更新.注意 ...
- poj 3468 A Simple Problem with Integers (线段树 成段更新 加值 求和)
题目链接 题意: 只有这两种操作 C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.&quo ...
- POJ3468_A Simple Problem with Integers(线段树/成段更新)
解题报告 题意: 略 思路: 线段树成段更新,区间求和. #include <iostream> #include <cstring> #include <cstdio& ...
- 线段树(成段更新) POJ 3468 A Simple Problem with Integers
题目传送门 /* 线段树-成段更新:裸题,成段增减,区间求和 注意:开long long:) */ #include <cstdio> #include <iostream> ...
- ACM: Copying Data 线段树-成段更新-解题报告
Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description W ...
- Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)
题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题 ...
- POJ 2777 Count Color (线段树成段更新+二进制思维)
题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的 ...
- HDU1698_Just a Hook(线段树/成段更新)
解题报告 题意: 原本区间1到n都是1,区间成段改变成一个值,求最后区间1到n的和. 思路: 线段树成段更新,区间去和. #include <iostream> #include < ...
随机推荐
- opensuse pptp拨号设置注意事项
防火墙一定要关闭 路由器要映射本地1723和1701端口 tcp协议(个别路由器和网络环境,可以先不设置) pptp配置注意协议的选择:
- EXT中的iconCls 图标加载
刚刚遇到了个奇怪的问题. 我用 在主页面用TAB autoLoad:{url:link, nocache: true, scripts:true} 加载页面Student.jsp, 郁闷,FF可以正常 ...
- 《asp.net mvc实战》笔记
对于大部分复杂的项目来说,可能不会在Models文件夹中放置你的模型.一般来说,最好的方法是将你的领域模型放在独立的项目中.这样其他应用程序可以在使用该项目而不必依赖于你的MVC应用程序.我们建议你只 ...
- Android四大组件之一:Activity
介绍:活动是最基本的Android组件之一,在应用程序中,一个活动通常就是一个用户界面,每一个活动都被实现为一个独立的类,并且从活动几类中继承, 活动类将会显示由View控件组成的用户接口,并对时间E ...
- GDAL Configure in Visual Studio 2010 for Win7/ GDAL+VisualStudio2010 Win7 配置
配置环境: OS:Win& *86 Ultimate Edition(EN) VS:Visual Studio 2010(EN) Step1: GDAL源码下载:http://www.gisi ...
- HDU 1954 Subway tree systems (树的最小表示法)
题意:用一个字符串表示树,0代表向下走,1代表往回走,求两棵树是否同构. 分析:同构的树经过最小表示会转化成两个相等的串. 方法:递归寻找每一棵子树,将根节点相同的子树的字符串按字典序排列,递归回去即 ...
- Linux 伙伴算法简介
本文将简要介绍一下Linux内核中的伙伴分配算法. Technorati 标签: 伙伴算法 算法作用 它要解决的问题是频繁地请求和释放不同大小的一组连续页框,必然导致在已分配 ...
- 不同浏览器的DNS超时重发机制(一)
一.Chrome浏览器(37.0.2062.124 m) 1.在Win7环境下,DNS超时重发的时间间隔为:2s.2s.2s.2s(在这个时刻重复发2个DNS请求).2s.4s,再经过大约14s左右, ...
- Windows 8.1 序列化与反序列化
/// <summary> /// 对象序列化成 XML String /// </summary> public static void XmlSerialize<T& ...
- Cookie与Session详解
来源:<PHP核心技术与最佳实践> 列旭松 陈文 著 Cookie与Session详解读书笔记,从概念.操作.应用.注意事项以及区别等几方面详细阐述两者的基础知识,它们都是针对HTTP协议 ...