接下來我們來填一下這個坑
回到我們的主題:noi 2005維修數列
我們剛剛討論了區間翻轉的操作方法,接下來我們來考慮區間插入和區間刪除的方法。
所以當我們插入一段區間的時候,我們還是把這個區間的前驅和後繼轉上去,然後把這段區間插到左子樹就可以了
等等,怎麼插?
乙個乙個往上扔?
這顯然是不合理的。
合理的方法是,將所有資料先建成一棵樹,然後直接把這棵樹掛到左子節點上即可。
可是這樣時間不會爆嗎?
當然不會!
為什麼?
我們稍微分析一下,每次建樹都是o(nlog2n)的,而插入數字總數不超過4000000,也就是說,即使我們一次性將這些數全插進去,也僅僅會有點卡常
何況正常情況下這麼多東西不會一口氣插進去,所以是完全不必擔心時間炸掉的。
那麼刪除一段區間也是同理了。
再往後,就是區間賦值了。
區間賦值和區間翻轉很接近,但是如果進行了區間賦值,那區間翻轉就沒有進行的必要了,所以操作的時候注意一下順序就好。
然後是維護區間和和維護最大子段和
區間求和操作類似線段樹,我們用乙個點維護他子樹的和,向上更新即可
最大子段和類似小白逛公園,由維護左聯通,右聯通和全區間的最優解,向上合併即可
(所以有人吐槽,說這題是1/6的線段樹,1/6小白逛公園,1/6文藝平衡樹,還有1/2不知道什麼玩意的東西)
還需要一些細節問題:
雖然說要扔進去4000000個數,但事實上,乙個序列中不過500000個數,所以splay空間開到500000左右就行
可是剩下那些如果直接扔就立刻re啦
所以我們開乙個佇列,把原來刪除的數的編號儲存起來,做乙個清理垃圾的機制,這樣就可以保證空間不**了。
那麼這樣的話,每個根的編號就會有變化,所以我們要用乙個對映getid,記錄多餘的編號
可是如果這麼操作,編號是很混亂的,所以我們就需要上面提到的find函式來查到這個端點在splay中真實的根。
最後是噁心的**...
#include #include #include #include #include #include #include #include #define inf 0x3f3f3f3f
#define ls tree[rt].lson
#define rs tree[rt].rson
using namespace std;
struct splay
tree[1000005];
int getid[500005];
int a[500005];
int cnt=0;
int rot;
int n,m;
char s[10];
queue m;
inline int read()
while(ch>='0'&&ch<='9')
return x*f;
}void update(int rt)
void cleanrubbish(int rt)
if(rs)
m.push(rt);
tree[rt].ttag=tree[rt].ctag=tree[rt].fa=ls=rs=0;
}void pushdown(int rt)
if(rs)
if(tree[rt].val>=0)
if(rs)
}else
if(rs)}}
if(tree[rt].ttag)
}int findf(int rt,int v)
else if(tree[ls].huge>=v)
else
}void rotate(int st,int &to)
else
if(v1==to)
else
else
}if(ltyp)
else
update(v1);
update(st);
}void splay(int st,int &to)
else
}rotate(st,to);
}}int split(int st,int len)
void reverse(int st,int len)
}void buildtree(int l,int r,int f)
if(mid>l)
if(mid>1];
int v1=findf(rot,st+1);
int v2=findf(rot,st+2);
splay(v1,rot);
splay(v2,tree[rot].rson);
tree[v2].lson=v;
tree[v].fa=v2;
update(v2);
update(v1);
}void del(int st,int len)
void changesame(int st,int len,int v)
else
update(tree[v1].fa);
update(tree[tree[v1].fa].fa);
}int query(int st,int len)
int main()
getid[n+1]=n+1;
getid[n+2]=n+2;
buildtree(1,n+2,0);
rot=(n+3)>>1,cnt=n+2;
while(m--)
else if(s[0]=='d')
else if(s[0]=='r')
else if(s[0]=='g')
else if(s[2]=='x')
else
}return 0;
}
SPLAY,LCT學習筆記(五)
這一篇重點 lct的應用 例 bzoj 2631 tree2 國家集訓隊 lct模板操作之一,利用splay可以進行區間操作這一性質對維護懶惰標記,注意標記下傳順序和如何下傳 include include include include include include include includ...
SPLAY,LCT學習筆記(六)
這應該暫時是個終結篇了.最後在這裡討論lct的乙個常用操作 維護虛子樹資訊 這也是乙個常用操作 下面我們看一下如何來維護 以下內容 對於乙個點x,如果我們對x進行access操作,那麼他的虛子樹內將包含且僅包含他原樹中子樹內除了他自己以外的所有點,這時如果我們維護了他的虛子樹資訊和,我們把這個資訊與...
SPLAY,LCT學習筆記(三)
前兩篇講述了splay模板操作,這一篇稍微介紹一下splay的實際應用 其實只有一道題,因為本蒟蒻就寫了這乙個 例 bzoj 1014火星人prefix 由於本蒟蒻不會字尾陣列,所以題目中給的提示完全沒看懂 不過並不影響我們做這道題,因為正解好像不用字尾陣列.首先,如果這題沒有插入和修改,那麼我們只...