P2572 SCOI2010 序列操作

2022-08-20 00:39:14 字數 3236 閱讀 6061

線段樹神仙操作==珂朵莉樹基本操作???

珂朵莉樹是不可能的,這輩子只會碼線段樹,只有線段樹神仙操作才刺激,debug之後ac才最快樂

這題我折騰了半個下午加半個晚上。維護的東西太多了。

如果沒有區間反轉,這題很簡單,但是有反轉,所以既要維護1,又要維護0。

tot記錄區間中1的個數

len記錄區間長度

l記錄區間左端點

r記錄區間右端點

sum1表示區間中最長連續的1的個數

lmax1表示區間中以左端點為起點從左往右的連續1的個數

rmax1表示區間中以右端點為起點從右往左的連續1的個數

0同理laz1表示區間覆蓋,0表示無操作,1表示0覆蓋,2表示1覆蓋

laz2表示區間反轉,0表示無操作,1表示反轉

定義了這麼多就夠了,然後考慮建樹和update維護

update:

1.tot就直接加就行

2.lmax1更新要看一下左區間是否全為1,若全為1,則應加上右區間lmax1

3.rmax1更新要看一下右區間是否全為1,若全為1,則應加上左區間rmax1

4.sum1更新有三個**,左區間sum1,右區間sum1,左區間rmax1+右區間lmax1

0維護的同理。

懶得寫那多if,else,所以這裡直接採用了三目運算子

build:

1.邊找邊求len

2.遞迴到葉子結點,看原序列中是1還是0,去更新葉子結點的東西

3.三目運算子對1和0的更新相反

4.最後update,由葉子結點回溯,維護整個大區間

然後基本的建樹完成了,先不想那些個操作,把main框架寫出,

change可以分標記表示修改操作,乙個就夠了

ask返回的東西不同,要分兩個

然後main函式也搞定了

開始本題比較難理解的一塊:down和laz標記。

1.如果之前有反轉標記,但是又有覆蓋標記,之前的反轉標記就沒用了

,所以當要打覆蓋標記時,反轉標記是可以清空的

2.區間覆蓋的話就是那些東西等於len或0的問題

3.區間反轉把0和1的東西交換就行了

4.down完標記記得清空

ask1返回tot就行

ask2分開找區間的話,還有可能是左區間的rmax1+右區間的lmax1,

這個還要取min,因為可能分到兩個區間的長度到不了lmax1或rmax1

值得注意的是直接下放標記可能葉子結點也下放,可能會越界,所以 開了八倍空間

#include#include

#define r register

#define lson k<<1,l,mid //減少碼量或者為了好看

#define rson k<<1|1,mid+1,r

#define ls k<<1

#define rs k<<1|1

#define mid ((l+r)>>1)

#define sum1(rt) tr[rt].sum1

#define sum0(rt) tr[rt].sum0

#define lmax1(rt) tr[rt].lmax1

#define lmax0(rt) tr[rt].lmax0

#define rmax1(rt) tr[rt].rmax1

#define rmax0(rt) tr[rt].rmax0

#define len(rt) tr[rt].len

#define laz1(rt) tr[rt].laz1

#define laz2(rt) tr[rt].laz2

#define tot(rt) tr[rt].tot

using

namespace

std;

const

int maxn=200005

;int

n,m,a[maxn];

struct

nodetr[maxn

<<2

];inline

intread()

while(ch>='

0'&&ch<='9')

return s*w;

}inline

void update(r int

k)void build(r int k,r int l,r int

r) build(lson);build(rson);

update(k);

}inline

void down(r int

k)

if(laz1(k)==2

)

if(laz2(k))

}void change(r int k,r int l,r int r,r int x,r int y,r int

z)

else

if(z==2

)

else

return

; }

if(y<=mid)change(lson,x,y,z);

else

if(x>mid)change(rson,x,y,z);

else change(lson,x,mid,z),change(rson,mid+1

,y,z);

update(k);

}int ask1(r int k,r int l,r int r,r int x,r int

y)

if(y<=mid)return

ask1(lson,x,y);

else

if(x>mid)return

ask1(rson,x,y);

else

return ask1(lson,x,mid)+ask1(rson,mid+1

,y);

}int ask2(r int k,r int l,r int r,r int x,r int

y)

if(y<=mid)return

ask2(lson,x,y);

else

if(x>mid)return

ask2(rson,x,y);

else

return max(max(ask2(lson,x,mid),ask2(rson,mid+1,y)),min(lmax1(rs),y-mid)+min(rmax1(ls),mid-x+1

));}

intmain()

return0;

}

P2572 SCOI2010 序列操作

include include define n 100005 using namespace std int n,m struct seg t n 2 共13個成員 void rev int k 第k個點取反 在外層修改了取反標誌 void color int k,int v 第k個點全改成0 1...

P2572 SCOI2010 序列操作

對自己 rng 驕兵必敗 lpl 加油!題目描述 lxhgww最近收到了乙個01序列,序列裡面包含了n個數,這些數要麼是0,要麼是1,現在對於這個序列有五種變換操作和詢問操作 0 a b 把 a,b 區間內的所有數全變成0 1 a b 把 a,b 區間內的所有數全變成1 2 a b 把 a,b 區間...

P2572 SCOI2010 序列操作

這道題給你好多的01串,還有好多的區間統一賦值。沒錯,你想到了什麼?珂朵莉樹!所以你就可以用珂朵莉樹很輕鬆地水過這道題了!唯一要注意的是split的順序。必須先split右邊的,再split左邊的。原因是先split左邊的時候,可能會因為split右邊而導致原迭代器被刪掉了,所以左邊的迭代器會是乙個...