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的操作

Output

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

Hint

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

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

Solution

测试题……睿智线段树……头一次写多标记线段树写了7k然后爆10分……最后发现标记传错了……

考虑一个区间维护的信息显然有1的个数,连续1长度,左连续1,右连续1。0也同理。标记打上区间置零,赋一,取反。

考虑pushdown操作。

发现这三个标记只能同时存在一个,所以下传的顺序是无所谓的。但是需要考虑打标记的时候标记的重叠问题。具体的,在make_tag的时候,如果打赋1标记,若存在取反标记,则改为打赋0标记。同时把其余标记置为false。区间置0同理。

考虑区间取反的时候,如果存在全部赋值标记,则将赋值标记取反,不打取反标记,否则将取反标记取反。因为把取反写成赋true爆10分了……

大概就这样

我好菜啊……写了7k只有10分

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long typedef long long int ll; namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
} template <typename T>
inline void qr(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
} template <typename T>
inline void ReadDb(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
} namespace OPT {
char buf[120];
} template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
rg int top=0;
do {OPT::buf[++top] = x % 10 + '0';} while ( x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
} const int maxn = 100010;
const int maxt = 200010; int n, m;
int MU[maxn]; struct Tag {
bool zero,one,bk;
inline void clear() {
zero = one = bk = false;
}
}; struct Info {
int s0, s1, len0, len1, ll0, ll1, rl0, rl1; inline void buildit(int _v) {
if (_v == 1) {
len1 = ll1 = rl1 = s1 = 1;
} else {
len0 = ll0 = rl0 = s0 = 1;
}
} inline void clear() {
s0 = s1 = len0 = len1 = ll0 = ll1 = rl0 = rl1 = 0;
} inline Info operator+(const Info &_others) const {
Info _ret;
_ret.clear();
_ret.s0 = this->s0 + _others.s0;
_ret.s1 = this->s1 + _others.s1;
_ret.len0 = std::max(std::max(this->len0,_others.len0), this->rl0 + _others.ll0);
_ret.len1 = std::max(std::max(this->len1,_others.len1), this->rl1 + _others.ll1);
_ret.ll0 = this->ll0 + (!this->s1) * (_others.ll0);
_ret.ll1 = this->ll1 + (!this->s0) * (_others.ll1);
_ret.rl0 = _others.rl0 + (!_others.s1) * (this->rl0);
_ret.rl1 = _others.rl1 + (!_others.s0) * (this->rl1);
return _ret;
} inline void reset(ci k) {
if (k == 0) {
this->s0 = this->ll0 = this->len0 = this->rl0 = this->s0 + this->s1;
this->s1 = this->len1 = this->ll1 = this->rl1 = 0;
} else if (k == 1) {
this->s1 = this->ll1 = this->len1 = this->rl1 = this->s0 + this->s1;
this->s0 = this->len0 = this->ll0 = this->rl0 = 0;
} else {
std::swap(this->s0,this->s1);
std::swap(this->ll0,this->ll1);
std::swap(this->len0,this->len1);
std::swap(this->rl0,this->rl1);
}
} }; struct Tree {
Tree *ls, *rs;
int l, r;
Tag tg;
Info v; inline void pushup() {
this->v.clear();
if((this->ls) && (!this->rs)) this->v = this->ls->v;
else if((this->rs) && (!this->ls)) this->v = this->rs->v;
else this->v = this->ls->v + this->rs->v;
} inline void maketag(ci k) {
if(k == 0) {
this->tg.zero = true;
this->v.reset(0);
this->tg.one = this->tg.bk = false;
} else if(k == 1) {
this->tg.one = true;
this->v.reset(1);
this->tg.zero = this->tg.bk = false;
} else {
if(this->tg.one) {
this->v.reset(0);
std::swap(this->tg.one,this->tg.zero);
} else if(this->tg.zero) {
this->v.reset(1);
std::swap(this->tg.one,this->tg.zero);
} else {
this->v.reset(2);
this->tg.bk ^= 1;
}
}
} inline void pushdown() {
if (this->tg.zero) {
if(this->ls) this->ls->maketag(0);
if(this->rs) this->rs->maketag(0);
} else if (this->tg.one) {
if(this->ls) this->ls->maketag(1);
if(this->rs) this->rs->maketag(1);
} else if(this->tg.bk) {
if(this->ls) this->ls->maketag(2);
if(this->rs) this->rs->maketag(2);
}
this->tg.clear();
}
};
Tree *pool[maxt], qwq[maxt], *rot;
int top; struct Ret {
int l,r,ans;
bool isall;
inline void clear() {
l = r = ans = isall = 0;
}
}; void buildpool();
void buildroot();
void build(Tree*, ci, ci);
void update(Tree*, ci, ci, ci);
int ask3(Tree*, ci, ci);
Ret ask4(Tree*, ci, ci); int main() {
freopen("data.in", "r", stdin);
qr(n); qr(m);
for (rg int i = 1; i <= n; ++i) qr(MU[i]);
buildpool();
buildroot();
build(rot, 1, n);
int a, b, c;
while (m--) {
a = b = c = 0;
qr(a); qr(b); qr(c);
++b;++c;
switch(a) {
case 0: {
update(rot, b, c, 0);
break;
}
case 1: {
update(rot, b, c, 1);
break;
}
case 2: {
update(rot, b, c, 2);
break;
}
case 3: {
qw(ask3(rot, b, c), '\n', true);
break;
}
case 4: {
qw(ask4(rot, b, c).ans, '\n', true);
break;
}
}
}
} void buildpool() {
for (rg int i = 0; i < maxt; ++i) pool[i] = qwq+i;
top = maxt - 1;
} void buildroot() {
rot = pool[top--];
rot->l = 1; rot->r = n;
} void build(Tree *u, ci l, ci r) {
if(l == r) {u->v.buildit(MU[l]); return;}
int mid = (l + r) >> 1;
if (l <= mid) {
u->ls = pool[top--];
u->ls->l = l; u->ls->r = mid;
build(u->ls, l, mid);
}
if(mid < r) {
u->rs = pool[top--];
u->rs->l = mid+1; u->rs->r = r;
build(u->rs, mid+1, r);
}
u->pushup();
} void update(Tree *u, ci l, ci r, ci v) {
u->pushdown();
if((u->l >= l) && (u->r <= r)) {
u->maketag(v);return;
}
if((u->l > r) || (u->r < l)) return;
if(u->ls) update(u->ls, l, r, v);
if(u->rs) update(u->rs, l, r, v);
u->pushup();
} int ask3(Tree *u, ci l, ci r) {
u->pushdown();
if((u->l >= l) && (u->r <= r)) return u->v.s1;
else if((u->l > r) || (u->r < l)) return 0;
int _ret = 0;
if(u->ls) _ret = ask3(u->ls, l ,r);
if(u->rs) _ret += ask3(u->rs, l, r);
return _ret;
} Ret ask4(Tree *u, ci l, ci r) {
u->pushdown();
if((u->l >= l) && (u->r <= r)) {
return (Ret){u->v.ll1, u->v.rl1, u->v.len1, u->v.s0 == 0};
}
if((u->l > r) || (u->r < l)) {
return (Ret){0, 0, 0, 0};
}
Ret rl,rr,ret;
rl.clear();rr.clear();ret.clear();
if(u->ls) rl = ask4(u->ls, l, r);
if(u->rs) rr = ask4(u->rs, l, r);
ret.l = rl.l + rl.isall * rr.l;
ret.r = rr.r + rr.isall * rl.r;
ret.ans = std::max(std::max(rl.ans, rr.ans), rl.r + rr.l);
return ret;
}

Summary

在多标记下传时,考虑下传顺序间的影响,以及下传新标记时,旧标记对新标记的影响。

另外比赛时如果正解写挂一定要及时写暴力……

【线段树】【P2572】【SCOI2010】序列操作的更多相关文章

  1. 【题解】Luogu P2572 [SCOI2010]序列操作

    原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 ...

  2. P2572 [SCOI2010]序列操作

    对自己 & \(RNG\) : 骄兵必败 \(lpl\)加油! P2572 [SCOI2010]序列操作 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要 ...

  3. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

  4. 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树

    正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...

  5. 洛谷P2572 [SCOI2010]序列操作(珂朵莉树)

    传送门 珂朵莉树是个吼东西啊 这题线段树代码4k起步……珂朵莉树只要2k…… 虽然因为这题数据不随机所以珂朵莉树的复杂度实际上是错的…… 然而能过就行对不对…… (不过要是到时候noip我还真不敢打… ...

  6. 洛谷 P2572 [SCOI2010]序列操作

    题意简述 维护一个序列,支持如下操作 把[a, b]区间内的所有数全变成0 把[a, b]区间内的所有数全变成1 把[a,b]区间内所有的0变成1,所有的1变成0 询问[a, b]区间内总共有多少个1 ...

  7. 洛谷P2572 [SCOI2010]序列操作

    线段树 pushdown写的很浪~ #include<cstdio> #include<cstdlib> #include<algorithm> #include& ...

  8. 洛谷P2572 [SCOI2010]序列操作(ODT)

    题解 题意 题目链接 Sol ODT板子题..... // luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long l ...

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

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

  10. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

随机推荐

  1. <力荐>非常好的正则表达式的详解<力荐>

    正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串.将匹配的子串做替换或者从某个串中取出符合某个条件的子串等. 列目录时, dir *.t ...

  2. Cube Stacking P0J 1988(加权并查集)

    Description Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes ...

  3. Alpha冲刺——第十天

    Alpha第十天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  4. timestamp 学习

    该答案摘抄自CSDN. 哇,奇迹,跨度三年了,不知道楼主是否已经解决了此问题. 路过,简单说一下,timestamp 主要是记录该行的最后修改时间戳, 注意,这个时间戳是不可以转换为时间的,只能标注该 ...

  5. L1正则化与L2正则化的理解

    1. 为什么要使用正则化   我们先回顾一下房价预测的例子.以下是使用多项式回归来拟合房价预测的数据:   可以看出,左图拟合较为合适,而右图过拟合.如果想要解决右图中的过拟合问题,需要能够使得 $ ...

  6. Jmeter 快速入门--简单的http压测

    1.添加线程组 打开jmeter主窗口后,选择左侧树形结构里的"测试计划",然后右键选择添加,选择"threads(users)",选择"线程组&qu ...

  7. Linux的计划任务

    1. 语法格式:Minute Hour DayOfMonth Month DayOfWeek User Command Minute, 每个小时的第几分钟执行该任务Hour,每天的第几个小时执行该任务 ...

  8. HttpClient出现大量time_wait问题

    在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接.这个场景下会出现大量socket处于TIME_WAIT状态.如果客户端的并发量持续很高,此时部分客户端就会显示连接不上.我来解 ...

  9. python脚本批量生成50000条插入数据的sql语句

    f = open("xx.txt",'w') for i in range(1,50001): str_i = str(i) realname = "lxs"+ ...

  10. bzoj5127[Lydsy12月赛]数据校验

    多少年不写题解了 题目描述: 著名出题人小 Q 出了一道题,这个题给定一个正整数序列 a1, a2, ..., an,并保证输入数据中,对于 a 的任意一个非空连续子区间 [l, r],该区间内出现过 ...