ETT学习笔记
ETT(Eular Tour Tree)是一種維護(hù)有根樹(shù)的數(shù)據(jù)結(jié)構(gòu),支持以下操作
據(jù)說(shuō)可以支持換根,但用的不多而且據(jù)說(shuō)很難寫(xiě),所以似乎失傳了(
其實(shí)沒(méi)啥技術(shù)含量,顧名思義就是維護(hù)一棵樹(shù)的歐拉序。
歐拉序指在 dfs 開(kāi)始和結(jié)束時(shí)分別將當(dāng)前點(diǎn)加入序列中,也稱(chēng)括號(hào)序。
用區(qū)間平衡樹(shù)維護(hù)這個(gè)歐拉序。
平衡樹(shù)不寫(xiě) treap ,根本不是人
每個(gè)點(diǎn)第一次插入的權(quán)值為題目給定的權(quán)值,第二次插入時(shí)取相反數(shù),要在平衡樹(shù)上記錄下這個(gè)符號(hào),并記錄下 每個(gè)原樹(shù)上的點(diǎn) 兩次插入時(shí) 在平衡樹(shù)上的點(diǎn) 的編號(hào)。
對(duì)treap額外維護(hù)平衡樹(shù)上的父結(jié)點(diǎn) fa,然后可以找到給定編號(hào)的結(jié)點(diǎn)在平衡樹(shù)上的排名。
單點(diǎn)操作直接搞就可以了。
因?yàn)闅W拉序上一個(gè)子樹(shù)對(duì)應(yīng)的是一個(gè)括號(hào),子樹(shù)修改時(shí)直接修改這個(gè)括號(hào)的區(qū)間。注意每個(gè)點(diǎn)要分別乘上自己的符號(hào),可以通過(guò)記錄平衡樹(shù)的子樹(shù)的符號(hào)之和實(shí)現(xiàn)。
對(duì)于鏈查詢(xún),不難看出是這個(gè)點(diǎn)第一次出現(xiàn)的位置的前綴和,直接查詢(xún)即可。
修改父親直接把整個(gè)括號(hào)提出來(lái)插進(jìn)新父親第一次位置的后面。
復(fù)雜度是O(nlog?n)O(n\log n)O(nlogn),跑得比較慢
模板題
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <cstdlib> #include <cassert> #define MAXN 200005 #define MAXM 400005 using namespace std; inline char gal() {char c=getchar();while (!isalpha(c)) c=getchar();return c; } inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } typedef long long ll; vector<int> e[MAXN]; int w[MAXN]; int sig[MAXN],ind[MAXN],siz[MAXN],rad[MAXN],ch[MAXN][2],fa[MAXN],tot; ll val[MAXN],sum[MAXN],lzy[MAXN]; inline int newnode(int v,int type) {++tot,siz[tot]=1,sum[tot]=val[tot]=v*type,sig[tot]=ind[tot]=type,rad[tot]=rand();return tot; } inline void update(int x) {siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1,ind[x]=ind[ch[x][0]]+ind[ch[x][1]]+sig[x];sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x]; } inline void pushlzy(int x,ll v){val[x]+=sig[x]*v,sum[x]+=v*ind[x],lzy[x]+=v;} inline void pushdown(int x) {if (lzy[x]){if (ch[x][0]) pushlzy(ch[x][0],lzy[x]);if (ch[x][1]) pushlzy(ch[x][1],lzy[x]);lzy[x]=0;} } int merge(int x,int y) {if (!x||!y) return x|y;pushdown(x),pushdown(y);if (rad[x]<rad[y]) return ch[x][1]=merge(ch[x][1],y),ch[x][1]&&(fa[ch[x][1]]=x),update(x),x;return ch[y][0]=merge(x,ch[y][0]),ch[y][0]&&(fa[ch[y][0]]=y),update(y),y; } void split(int x,int k,int& l,int& r) {if (!x) return (void)(l=r=0);pushdown(x);if (k<=siz[ch[x][0]]) split(ch[x][0],k,l,r),fa[ch[x][0]]=0,ch[x][0]=r,r&&(fa[r]=x),update(x),r=x;else split(ch[x][1],k-siz[ch[x][0]]-1,l,r),fa[ch[x][1]]=0,ch[x][1]=l,l&&(fa[l]=x),update(x),l=x; } int rt,l[MAXN],r[MAXN]; inline void modify(int l,int r,int v) {int a,b,c,d;split(rt,l-1,a,d);split(d,r-l+1,b,c);pushlzy(b,v);rt=merge(merge(a,b),c); } inline int getrk(int x) {int f=1,ans=0;while (x){if (f) ans+=siz[ch[x][0]]+1;f=(ch[fa[x]][1]==x),x=fa[x];}return ans; } void dfs(int u) {int t;t=merge(rt,l[u]=newnode(w[u],1)),rt=t;for (int i=0;i<(int)e[u].size();i++) dfs(e[u][i]);t=merge(rt,r[u]=newnode(w[u],-1)),rt=t; } int main() {int n=read();for (int i=2;i<=n;i++) e[read()].push_back(i);for (int i=1;i<=n;i++) w[i]=read();dfs(1);for (int T=read();T;T--){char op=gal();if (op=='Q') {int a,b;split(rt,getrk(l[read()]),a,b);printf("%lld\n",sum[a]);rt=merge(a,b);}if (op=='C'){int x,y;x=read(),y=read();int a,b,c,d,e;split(rt,getrk(l[x])-1,a,d);split(d,getrk(r[x]),b,c);e=merge(a,c);split(e,getrk(l[y]),a,c);rt=merge(merge(a,b),c);}if (op=='F'){int x,v;x=read(),v=read();modify(getrk(l[x]),getrk(r[x]),v);}}return 0; }總結(jié)
- 上一篇: 【WC2016】挑战NPC 【带花树】【
- 下一篇: 唾液腺分泌唾液不受大脑控制怎么回事?