jerry3128
2021-04-26 13:12:33
Video Access: https://www.bilibili.com/video/BV1Hh8qeGEgt
本文着重介绍几类 ETT 的实现方式与其对应的维护信息,分析其在各种信息维护上的优劣。
首先来介绍几种基于欧拉环游序和其的省略或者类似的版本。目前笔者自己研究的独立 ETT 仅能做到自由 link-cut 维护子树信息,要求交换律与结合律。
下面就来介绍几种实用的例子。
题目大意:
题解:splay & 括号序。
//ayame保佑,夸哥保佑,狗妈保佑,MDR保佑,锉刀怪保佑,M99保佑,克爹保佑
#include<bits/stdc++.h>
using namespace std;
int p1=1000000,p2=0;
char buf[1000005],wb[1000005];
int gc() {
if(p1>=1000000)fread(buf,1,1000000,stdin),p1=0;
return buf[p1++];
}
#define gc getchar
#define Loli true
#define Kon xor true
long long getint() {
long long ret=0,flag=1;
char c=gc();
while(c<'0'||c>'9') {
if(c=='-')flag=-1;
c=gc();
}
while(c<='9'&&c>='0') {
ret=(ret<<3)+(ret<<1)+c-'0';
c=gc();
}
return ret*flag;
}
void pc(char x) {
if(p2>=1000000)fwrite(wb,1,1000000,stdout),p2=0;
wb[p2++]=x;
}
void wrt(long long x) {
if(x<0)pc('-'),x=-x;
int c[24]= {0};
if(!x)return pc('0'),void();
while(x)c[++c[0]]=x%10,x/=10;
while(c[0])pc(c[c[0]--]+'0');
}
int n,m,a[100005];
int fa[100005],dep[100005];
int o[100005][31],prt[20][100005];
namespace ETT {
struct node {
int ch[2],fa,pre,suf;
int vl,sz,dep,mx,mi,etag,stag;
int col,ctag;
} v[200005];
void push_down(int rt) {
if(v[rt].ctag) {
if(v[rt].ch[0])v[v[rt].ch[0]].ctag=v[v[rt].ch[0]].col=v[rt].ctag;
if(v[rt].ch[1])v[v[rt].ch[1]].ctag=v[v[rt].ch[1]].col=v[rt].ctag;
v[rt].ctag=0;
}
}
void push_up(int rt) {
v[rt].pre=v[rt].suf=rt;
v[rt].mx=v[rt].mi=v[rt].dep;
if(v[rt].ch[0])v[rt].pre=v[v[rt].ch[0]].pre,v[rt].mx=max(v[rt].mx,v[v[rt].ch[0]].mx),v[rt].mi=min(v[rt].mi,v[v[rt].ch[0]].mi);
if(v[rt].ch[1])v[rt].suf=v[v[rt].ch[1]].suf,v[rt].mx=max(v[rt].mx,v[v[rt].ch[1]].mx),v[rt].mi=min(v[rt].mi,v[v[rt].ch[1]].mi);
v[rt].stag=v[rt].etag|v[v[rt].ch[0]].stag|v[v[rt].ch[1]].stag;
v[rt].sz=v[v[rt].ch[0]].sz+v[rt].vl+v[v[rt].ch[1]].sz;
}
void rot(int x) {
int p=v[x].fa,g=v[p].fa;
bool d=v[p].ch[1]==x;
if(g)v[g].ch[v[g].ch[1]==p]=x;
v[p].ch[d]=v[x].ch[d^1];
v[v[x].ch[d^1]].fa=p;
v[x].ch[d^1]=p;
v[x].fa=g,v[p].fa=x;
push_up(p),push_up(x);
}
void pre_push_down(int rt) {
if(v[rt].fa)pre_push_down(v[rt].fa);
push_down(rt);
}
void splay(int x,int f=0) {
if(!x)return;
pre_push_down(x);
while(v[x].fa!=f) {
int p=v[x].fa,g=v[p].fa;
if(g!=f)rot(v[g].ch[0]==p^v[p].ch[0]==x?x:p);
rot(x);
}
}
void init() {
for(int i=1; i<=n; i++) {
v[i<<1].vl=1,v[i<<1].ch[1]=i<<1|1,v[i<<1|1].fa=i<<1,v[i<<1].col=a[i];
v[i<<1].dep=v[i<<1|1].dep=dep[i],push_up(i<<1|1),push_up(i<<1);
}
}
int merge_bro(int x,int y) {
if(!x||!y)return x|y;
splay(x),splay(y);
int d=v[x].suf;
splay(d),v[d].ch[1]=y,v[y].fa=d,push_up(d);
return x;
}
void merge_prt(int x,int y) {
splay(x<<1),splay(v[v[x<<1].ch[1]].pre,x<<1),splay(y);
v[v[x<<1].ch[1]].ch[0]=y,v[y].fa=v[x<<1].ch[1],push_up(v[x<<1].ch[1]),push_up(x<<1);
}
int ask(int x) {
if(x==0)return x;
return splay(x),v[x].pre;
}
void dfs(int x,int c,vector<int>&vec) {
push_down(x);
if(v[x].etag>>c&1)vec.push_back(x>>1),v[x].etag^=1<<c;
if(v[v[x].ch[0]].stag>>c&1)dfs(v[x].ch[0],c,vec);
if(v[v[x].ch[1]].stag>>c&1)dfs(v[x].ch[1],c,vec);
push_up(x);
}
}
void ask(int x) {
int p=x;
for(int i=19; i>=0; i--)if(ETT::ask(p<<1)==ETT::ask(prt[i][p]<<1))p=prt[i][p];
ETT::splay(p<<1),ETT::splay(p<<1|1,p<<1);
int sz=ETT::v[ETT::v[p<<1|1].ch[0]].sz+1,len=max(ETT::v[ETT::v[p<<1|1].ch[0]].mx-dep[p],0)+1;
wrt(ETT::v[p<<1].col),pc(' '),wrt(sz),pc(' '),wrt(len),pc('\n');
}
void paint_point(int x,int gc) {
int p=x;
for(int i=19; i>=0; i--)if(ETT::ask(p<<1)==ETT::ask(prt[i][p]<<1))p=prt[i][p];
ETT::splay(x<<1),ETT::splay(x<<1|1,x<<1);
int l=ETT::v[x<<1].ch[0],r=ETT::v[x<<1|1].ch[1],col=ETT::v[x<<1].col;
ETT::v[l].fa=0,ETT::v[r].fa=0,ETT::v[x<<1].ch[0]=0,ETT::v[x<<1|1].ch[1]=0;
ETT::push_up(x<<1|1),ETT::push_up(x<<1);
if(fa[x]) {
int tmp=ETT::merge_bro(l,r);
o[fa[p]][col]=tmp;
ETT::splay(fa[p]<<1);
if(!o[fa[p]][col])ETT::v[fa[p]<<1].etag^=1<<col;
ETT::push_up(fa[p]<<1);
} else ETT::merge_bro(l,r);
if(ETT::v[x<<1|1].ch[0]) {
int d=ETT::v[x<<1|1].ch[0];
ETT::v[d].fa=0,ETT::v[x<<1|1].ch[0]=0;
ETT::push_up(x<<1|1),ETT::push_up(x<<1);
o[x][col]=d,ETT::v[x<<1].etag|=1<<col,ETT::push_up(x<<1);
}
ETT::v[x<<1].col=ETT::v[x<<1|1].col=gc;
if(o[x][gc]) {
int d=o[x][gc];
o[x][gc]=0,ETT::splay(d),ETT::v[x<<1|1].ch[0]=d,ETT::v[d].fa=x<<1|1;
ETT::v[x<<1].etag^=1<<gc,ETT::push_up(x<<1|1),ETT::push_up(x<<1);
}
if(fa[x]) {
ETT::splay(fa[x]<<1);
if(gc!=ETT::v[fa[x]<<1].col) {
o[fa[x]][gc]=ETT::merge_bro(o[fa[x]][gc],x<<1);
ETT::splay(fa[x]<<1);
ETT::v[fa[x]<<1].etag|=1<<gc;
ETT::push_up(fa[x]<<1);
} else ETT::merge_prt(fa[x],x<<1);
}
}
void paint_block(int x,int gc) {
for(int i=19; i>=0; i--)if(ETT::ask(x<<1)==ETT::ask(prt[i][x]<<1))x=prt[i][x];
ETT::splay(x<<1),ETT::splay(x<<1|1,x<<1);
int l=ETT::v[x<<1].ch[0],r=ETT::v[x<<1|1].ch[1],col=ETT::v[x<<1].col;
ETT::v[l].fa=0,ETT::v[r].fa=0,ETT::v[x<<1].ch[0]=0,ETT::v[x<<1|1].ch[1]=0;
ETT::push_up(x<<1|1),ETT::push_up(x<<1);
if(fa[x]) {
o[fa[x]][col]=ETT::merge_bro(l,r);
ETT::splay(fa[x]<<1);
if(!o[fa[x]][col])ETT::v[fa[x]<<1].etag^=1<<col;
ETT::push_up(fa[x]<<1);
} else ETT::merge_bro(l,r);
ETT::v[x<<1].col=ETT::v[x<<1].ctag=gc;
vector<int> vec;
ETT::dfs(x<<1,gc,vec);
for(int w:vec)ETT::merge_prt(w,o[w][gc]),o[w][gc]=0;
if(fa[x]) {
ETT::splay(fa[x]<<1);
if(gc!=ETT::v[fa[x]<<1].col) {
o[fa[x]][gc]=ETT::merge_bro(o[fa[x]][gc],x<<1);
ETT::splay(fa[x]<<1);
ETT::v[fa[x]<<1].etag|=1<<gc;
ETT::push_up(fa[x]<<1);
} else ETT::merge_prt(fa[x],x<<1);
}
}
int main() {
n=getint();
for(int i=1; i<=n; i++)prt[0][i]=fa[i]=getint(),dep[i]=dep[fa[i]]+1;
for(int j=1; j<20; j++)
for(int i=1; i<=n; i++)prt[j][i]=prt[j-1][prt[j-1][i]];
for(int i=1; i<=n; i++)a[i]=getint();
ETT::init(),m=getint();
for(int i=n; i>=2; i--) {
if(a[fa[i]]==a[i])ETT::merge_prt(fa[i],i<<1);
else o[fa[i]][a[i]]=ETT::merge_bro(o[fa[i]][a[i]],i<<1),ETT::splay(fa[i]<<1),ETT::v[fa[i]<<1].etag|=1<<a[i],ETT::push_up(fa[i]<<1);
}
for(int i=1; i<=m; i++) {
int opt=getint();
if(opt==1) {
int x=getint(),c=getint();
paint_point(x,c);
}
if(opt==2) {
int x=getint(),c=getint();
paint_block(x,c);
}
if(opt==3)ask(getint());
}
fwrite(wb,1,p2,stdout);
return Loli Kon;
}
动态图的完全连通性与此类似,采用刚刚找边的均摊思想,但对 link - cut 的要求相对更强,用正反弧 ETT,和 HDLT 的分层图算法维护。