ETT学习笔记

本文深入探讨了ETT(Euler Tour Tree)数据结构,一种高效处理有根树的算法,支持点权修改、子树修改、单点查询、点到根路径查询及节点父级更改等操作。通过维护欧拉序和区间平衡树,ETT实现了对树结构的灵活操作,模板代码详实,适合算法竞赛和高级数据处理。

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 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值