線段樹神仙操作==珂朵莉樹基本操作???
珂朵莉樹是不可能的,這輩子只會碼線段樹,只有線段樹神仙操作才刺激,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右邊而導致原迭代器被刪掉了,所以左邊的迭代器會是乙個...