我們經常會用到這樣的代碼
if(mark[i])i++;//i--
很明顯,這個代碼是用來在序列上尋找距離當前節點最近的沒有被標記的節點
但這個代碼複雜度爲
於是我們可以運用線段樹的原理設計一個
我們用線段樹的每個節點代表一個區間
在樹上進行整個標記和查找的操作
在這棵樹上操作時,
需要尋找的是在當前節點
很顯然,如果當前區間全部被標記,需要繼續
並且,我們肯定是從
從它的左子樹
於是,如果我們是從左子樹
同樣的,如果當前節點的左子樹已被標記,也還需要繼續
至於
而找到了這個點之後就可以在樹上對其進行標記操作
代碼如下:
int tree[M<<2],A[M],B[M<<2];
//A代表序列中的點在樹上的編號
//B代表樹上的點在序列中的編號
//tree代表序列上某一區間是否全部被標記
void build(int l,int r,int p){
if(l==r){
A[l]=p;
B[p]=l;
return;
}
int mid=l+r>>1;
build(l,mid,(p<<1));
build(mid+1,r,(p<<1)|1);
}
int query(int p){
if(tree[p]){
int pre=p;p>>=1;
while(tree[p<<1]||pre==(p<<1)){
//①區間所有點都被標記過(包含於第②種情況,可以忽略)②該區間的左子樹中的點都被標記過③先前是從左子樹中up上來的
//這三種情況則需要繼續up
pre=p;
p>>=1;
}
p<<=1;
while(p&&!B[p]){
if(tree[(p<<1)|1])p<<=1;
else p=(p<<1)|1;
}
}
return p;
}
void update(int p){
do tree[p]=1,p>>=1;
while(!tree[p]&&tree[p<<1]&&tree[(p<<1)|1]);
}