0 L R 将[L,R]之间的数字都变成0;
1 L R 将[L,R]之间的数字都变成1;
2 L R 将[L R]之间的数字都取反;
3 L R 询问[L R]之间1的个数;
4 L R 询问[L,R]之间连续1的个数最大是多少.
第一眼:这sb题。。
第二眼:这sb题。。
第三眼:哎呀卧槽这儿取反和赋值俩标记咋搞???
大致脑补了一下,很不确定对不对,然后上网看了下别人的写法,也觉得很难想清楚。。
管他的,开始写吧!!
用啥数据结构?线段树?貌似很好写,但是线段树修改都还好,最要命的是询问的时候你还得拼凑答案。
那就treap吧。。treap可以split出来直接读取答案。
写了差不多40分钟终于写出来了,样例1A了。然后往codevs上叫只过了一个点。。
然后就开始2+hrs的Debug。。然后实在找不出错了。。然后就打算另辟蹊径,我不维护两个标记了,我直接维护两个treap!!空间没限制就是任性!!这两个treap每一位都相反,比如说第一个treap是01001,第二个就是10110,各自维护对应的信息,分开保存根。
每次题目要求<0 l r>操作的时候实际对第一个treap进行<0 l r>,对第二个进行<1 l r>;
操作<1 l r>类似;
每次题目要求<2 l r>操作的时候交换两个treap的[l,r]区间即可。
然后就只需要保存一个same标记啦!!!
然后就慢死了。。。常数略大。。。bzoj上跑了9s+。。
但是我觉得这种思路真的很实用!!!像这道题这样按位取反,还有经典的区间翻转都能用这种维护两个序列的方式来实现,从而避免多个懒标记下传顺序的讨论。更准确的说,如果一个操作连续对[l,r]作用两次后会恢复原状,就可以用这种方法。虽然牺牲一点常数时间,但是准确率大大提高了。。这种方法treap和splay都可以实现,但好像线段树不好做。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cassert>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
#define LL long long
typedef pair<int, int> pii;
const int MAXN = 100005*2;
#define fi first
#define se second
int N, M;
inline int ran()
{
static int sd = 1237;
return sd = (sd*12371237)&0x7fffffff;
}
struct Treap
{
int lch[MAXN], rch[MAXN], sz[MAXN], fix[MAXN];
int xt[MAXN], cnt[MAXN], val[MAXN];
int lx[MAXN][2], rx[MAXN][2], mx[MAXN][2];
int ncnt, r1, r2; //建两棵相反的treap来避免reverse标记
int L, R, flag;
inline void pushup(int x)
{
L = lch[x], R = rch[x];
sz[x] = sz[L] + sz[R] + 1;
cnt[x] = cnt[L] + cnt[R] + val[x];
rep(c, 0, 1)
{
flag = (val[x]==c);
if (mx[L][c] == sz[L]) lx[x][c] = sz[L] + flag + lx[R][c]*flag;
else lx[x][c] = lx[L][c];
if (mx[R][c] == sz[R]) rx[x][c] = sz[R] + flag + rx[L][c]*flag;
else rx[x][c] = rx[R][c];
mx[x][c] = max(mx[L][c], mx[R][c]);
if (flag) mx[x][c] = max(mx[x][c], rx[L][c]+1+lx[R][c]);
}
}
inline void upxt(int x, int v)
{
if (!x) return;
cnt[x] = (val[x]=v) * sz[x];
lx[x][v] = rx[x][v] = mx[x][v] = sz[x];
lx[x][!v] = rx[x][!v] = mx[x][!v] = 0;
xt[x] = v;
}
inline void pushdown(int x)
{
L = lch[x], R = rch[x];
if (~xt[x])
{
upxt(L, xt[x]), upxt(R, xt[x]);
xt[x] = -1;
}
}
int NewNode(int i)
{
++ncnt;
fix[ncnt] = ran();
cnt[ncnt] = val[ncnt] = i;
sz[ncnt] = 1;
lx[ncnt][i] = rx[ncnt][i] = mx[ncnt][i] = 1;
xt[ncnt] = -1;
return ncnt;
}
int merge(int a, int b)
{
if (!a || !b) return a|b;
pushdown(a), pushdown(b);
if (fix[a] > fix[b])
{
rch[a] = merge(rch[a], b);
return pushup(a), a;
}
else
{
lch[b] = merge(a, lch[b]);
return pushup(b), b;
}
}
pii split(int x, int k)
{
if (!x) return pii(0, 0);
pushdown(x);
pii y;
if (sz[lch[x]] >= k)
{
y = split(lch[x], k);
lch[x] = y.se, y.se = x;
}
else
{
y = split(rch[x], k - sz[lch[x]] - 1);
rch[x] = y.fi, y.fi = x;
}
return pushup(x), y;
}
int sta[MAXN];
int build(int*a, int n)
{
int x, las, p = 0;
rep(i, 1, n)
{
x = NewNode(a[i]);
las = 0;
while (p && fix[sta[p]] < fix[x])
pushup(las = sta[p]), sta[p--] = 0;
if (p) rch[sta[p]] = x;
lch[x] = las;
sta[++p] = x;
}
while (p) pushup(sta[p--]);
return sta[1];
}
void init(int*a, int n)
{
r1 = build(a, n);
rep(i, 1, n) a[i] ^= 1;
r2 = build(a, n);
}
void makesame(int l, int r, int v)
{
pii t1 = split(r1, l-1);
pii t2 = split(t1.se, r-l+1);
upxt(t2.fi, v);
r1 = merge(merge(t1.fi, t2.fi), t2.se);
t1 = split(r2, l-1);
t2 = split(t1.se, r-l+1);
upxt(t2.fi, !v);
r2 = merge(merge(t1.fi, t2.fi), t2.se);
}
void reverse(int l, int r)
{
pii t1 = split(r1, l-1);
pii t2 = split(t1.se, r-l+1);
pii t3 = split(r2, l-1);
pii t4 = split(t3.se, r-l+1);
r1 = merge(merge(t1.fi, t4.fi), t2.se);
r2 = merge(merge(t3.fi, t2.fi), t4.se);
}
int qcnt(int l, int r)
{
pii t1 = split(r1, l-1);
pii t2 = split(t1.se, r-l+1);
int ans = cnt[t2.fi];
r1 = merge(merge(t1.fi, t2.fi), t2.se);
return ans;
}
int qmx(int l, int r)
{
pii t1 = split(r1, l-1);
pii t2 = split(t1.se, r-l+1);
int ans = mx[t2.fi][1];
r1 = merge(merge(t1.fi, t2.fi), t2.se);
return ans;
}
} tp;
int s[MAXN];
int main()
{
freopen("data.txt", "r", stdin);
freopen("f.out", "w", stdout);
scanf("%d%d", &N, &M);
rep(i, 1, N) scanf("%d", s+i);
tp.init(s, N);
int op, l, r;
while (M --)
{
scanf("%d%d%d", &op, &l, &r);
l++, r++;
switch(op)
{
case 0: tp.makesame(l, r, 0); break;
case 1: tp.makesame(l, r, 1); break;
case 2: tp.reverse(l, r); break;
case 3: printf("%d\n", tp.qcnt(l, r)); break;
default:printf("%d\n", tp.qmx(l, r)); break;
}
}
return 0;
}