2025年ETT学习笔记

ETT学习笔记ETT Eular Tour Tree 是一种维护有根树的数据结构 支持以下操作 修改一个点的点权 子树修改 单点查询 点到根路径查询 修改一个点的父亲 据说可以支持换根 但用的不多而且据说很难写 所以似乎失传了 其实没啥技术含量 顾名思义就是维护一棵树的欧拉序 欧拉序指在

大家好,我是讯享网,很高兴认识大家。

ETT(Eular Tour Tree)是一种维护有根树的数据结构,支持以下操作

  1. 修改一个点的点权
  2. 子树修改
  3. 单点查询
  4. 点到根路径查询
  5. 修改一个点的父亲

据说可以支持换根,但用的不多而且据说很难写,所以似乎失传了(

其实没啥技术含量,顾名思义就是维护一棵树的欧拉序。

欧拉序指在 dfs 开始和结束时分别将当前点加入序列中,也称括号序。

用区间平衡树维护这个欧拉序。

平衡树不写 treap ,根本不是人

每个点第一次插入的权值为题目给定的权值,第二次插入时取相反数,要在平衡树上记录下这个符号,并记录下 每个原树上的点 两次插入时 在平衡树上的点 的编号。


讯享网

对treap额外维护平衡树上的父结点 fa,然后可以找到给定编号的结点在平衡树上的排名。

单点操作直接搞就可以了。

因为欧拉序上一个子树对应的是一个括号,子树修改时直接修改这个括号的区间。注意每个点要分别乘上自己的符号,可以通过记录平衡树的子树的符号之和实现。

对于链查询,不难看出是这个点第一次出现的位置的前缀和,直接查询即可。

修改父亲直接把整个括号提出来**新父亲第一次位置的后面。

复杂度是 O ( n log ⁡ n ) O(n\log n) O(nlogn),跑得比较慢

模板题

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <cstdlib> #include <cassert> #define MAXN  #define MAXM  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; } 

讯享网
小讯
上一篇 2025-03-22 16:24
下一篇 2025-01-10 09:12

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/68828.html