日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ETT学习笔记

發(fā)布時(shí)間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ETT学习笔记 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ETT(Eular Tour Tree)是一種維護(hù)有根樹的數(shù)據(jù)結(jié)構(gòu),支持以下操作

  • 修改一個(gè)點(diǎn)的點(diǎn)權(quán)
  • 子樹修改
  • 單點(diǎn)查詢
  • 點(diǎn)到根路徑查詢
  • 修改一個(gè)點(diǎn)的父親
  • 據(jù)說可以支持換根,但用的不多而且據(jù)說很難寫,所以似乎失傳了(

    其實(shí)沒啥技術(shù)含量,顧名思義就是維護(hù)一棵樹的歐拉序。

    歐拉序指在 dfs 開始和結(jié)束時(shí)分別將當(dāng)前點(diǎn)加入序列中,也稱括號序。

    用區(qū)間平衡樹維護(hù)這個(gè)歐拉序。

    平衡樹不寫 treap ,根本不是人

    每個(gè)點(diǎn)第一次插入的權(quán)值為題目給定的權(quán)值,第二次插入時(shí)取相反數(shù),要在平衡樹上記錄下這個(gè)符號,并記錄下 每個(gè)原樹上的點(diǎn) 兩次插入時(shí) 在平衡樹上的點(diǎn) 的編號。

    對treap額外維護(hù)平衡樹上的父結(jié)點(diǎn) fa,然后可以找到給定編號的結(jié)點(diǎn)在平衡樹上的排名。

    單點(diǎn)操作直接搞就可以了。

    因?yàn)闅W拉序上一個(gè)子樹對應(yīng)的是一個(gè)括號,子樹修改時(shí)直接修改這個(gè)括號的區(qū)間。注意每個(gè)點(diǎn)要分別乘上自己的符號,可以通過記錄平衡樹的子樹的符號之和實(shí)現(xiàn)。

    對于鏈查詢,不難看出是這個(gè)點(diǎn)第一次出現(xiàn)的位置的前綴和,直接查詢即可。

    修改父親直接把整個(gè)括號提出來插進(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é)

    以上是生活随笔為你收集整理的ETT学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。