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;
}