由于初学,对LCT各种操作还不是很会.
然后对于对边权操作和对点权操作还不熟悉, 所以大致分为两类。
第一类:修改更新边的权值:dfs建树:
void dfs(int u,int f)
{
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==f)continue;
fa[v]=u;
tree[v].cost=tree[v].maxcost=e[i].w;
tree[v].f=tree+u;
dfs(v,u);
}
}
第二类:修改点的权值:(先单独建立点的信息,再把点连起来)
node *newnode(int key)
{
f=cur->ch[0]=cur->ch[1]=null;
cur->mm=cur->key=key;
cur->add=0;
cur->rev=0;
return cur++;
}
void link(node *u,node *v)
{
access(u);
splay(u);
u->rev=1;
u->f=v;
}
而后可以记录两种东西保存是否是当前splay树的根,root标记或者isroot.
细节处理root上注意:
node *access(node *u)
{
node *v=null;
while(u!=null)
{
splay(u);
if(ok)
{
if(u->f==null)
{
printf("%d\n",max(u->ch[1]->maxcost,v->maxcost));
}
}
u->ch[1]->root=true;
u->ch[1]=v; //这两句交换了顺序就会错,但是我想不通
v->root=false;
pushup(u);
v=u;
u=u->f;
}
return v;
}
void rotate(node *u)
{
node *f=u->f;
node *ff=f->f;
int d=u==f->ch[1];
if(u->ch[d^1]!=null)u->ch[d^1]->f=f;
f->ch[d]=u->ch[d^1];
u->f=ff;
if(ff!=null)
{
if(f==ff->ch[0])ff->ch[0]=u;
else if(f==ff->ch[1])ff->ch[1]=u;
}
u->ch[d^1]=f;
f->f=u;
pushup(f);
pushup(u);
if(f->root)//每次rotate需要更新这里
{
u->root=true;
f->root=false;
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
☆☆☆☆☆对于建边,考虑了很久到底采用哪种版,最后总结出了一个适合自己的版。
//初始化点 null=&Tnull;init(null);
void init(node *u)
{
u->f=u->ch[0]=u->ch[1]=null;
u->rev=0;
u->cost=u->maxcost=u->add=0;
} //对于每个点都进行初始化
for(int i=1;i<=n;i++)
{
head[i]=-1;
init(&tree[i]);
}//初始化
读完信息后dfs建树:
void dfs(int u,int f)
{
tree[u].cost=tree[u].maxcost=det[u];
if(f!=-1)tree[u].f=tree+f;
else tree[u].f=null;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==f)continue;
dfs(v,u);
}
}
然后是对于root还是isroot()的选择。我觉得还是尽可能的选择isroot,函数也需要方便一点。
而且isroot不需要在更新的时候维护,而且可能要快一些:
上面的是isroot,下面的是root,不仅要快一些,空间也省了一些.
bool isroot(node *u)
{
return u==null||u->f->ch[0]!=u&&u->f->ch[1]!=u;
}
rev操作:对于link或者changeroot等操作需要rev标记,直接pushdown好了。
pushdown:在splay的时候开一个栈,然后把它到根这条路径上每个点先pushdown(从上到下).,一样的pushdown,lazy标记 (rev的优先级高于其他lazy?我不造)
void pushdown(node *u)
{
if(u==null)return ;
if(u->rev)//翻转lazy
{
swap(u->ch[0],u->ch[1]);
if(u->ch[0]!=null)u->ch[0]->rev^=1;
if(u->ch[1]!=null)u->ch[1]->rev^=1;
u->rev=0;
}
if(u->add)//增加lazy
{
if(u->ch[0]!=null)
{
u->ch[0]->cost+=u->add;
u->ch[0]->maxcost+=u->add;
u->ch[0]->add+=u->add;
}
if(u->ch[1]!=null)
{
u->ch[1]->cost+=u->add;
u->ch[1]->maxcost+=u->add;
u->ch[1]->add+=u->add;
}
u->add=0;
}
}
rotate:细节----每次rotate之后只需要更新f的信息就好了,不然多次updata会很慢。
(原理:参照论文http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 看它里面的rotate操作讲解)
其实简单点说就是rotate一定是在splay里面进行的,splay(u),u的信息只需要在最后更新就好了
void rotate(node *u)
{
node *f=u->f;
node *ff=f->f;
int d=u==f->ch[1];
if(u->ch[d^1]!=null)u->ch[d^1]->f=f;
f->ch[d]=u->ch[d^1];
if(ff!=null)
{
if(f==ff->ch[0])ff->ch[0]=u;
else if(f==ff->ch[1])ff->ch[1]=u;
}
u->f=ff;
f->f=u;
u->ch[d^1]=f;
pushup(f);
}
splay:(预处理pushdown)
void splay(node *u)
{
if(u==null)return ;
cnt=1;
sta[0]=u;
for(node *y=u;!isroot(y);y=y->f)
{
sta[cnt++]=y->f;
}
while(cnt)pushdown(sta[--cnt]);
while(!isroot(u))
{
node *f=u->f;
if(isroot(f))
{
rotate(u);
}
else
{
node *ff=f->f;
int d=u==f->ch[1];
int dd=f==ff->ch[1];
if(d==dd)rotate(f);
else rotate(u);
rotate(u);
}
}
pushup(u);
}
同一颗子树判断(一直往根找):
bool sam(node *u,node *v)
{
while(u->f!=null)u=u->f;
while(v->f!=null)v=v->f;
return u==v;
}
access(写成指针返回是利于changeroot)
node * access(node *u)
{
node *v=null;
while(u!=null)
{
splay(u);
u->ch[1]=v;
v->f=u;//和root写法不同
pushup(u);
v=u;
u=u->f;
}
return v;
}
link:原理:access之后u是它所在splay上深度最大的点,一定在最右边(该splay记录u到整棵树root的路径),splay之后就没有右子树,翻转之后它就是深度最小的点,就是根了,然后把这棵树接到v上就完成了合并
void link(node *u,node *v)
{
access(u);
splay(u);
u->rev=1;
u->f=v;
}
changeroot:原理同上,少一个操作
void changeroot(node *u)
{
access(u)->rev^=1;//access返回的是u所在splay的根(返回的是v,u==null所以v是根)
}
void cut(node *u)
{
access(u);
splay(u);
u->ch[0]=u->ch[0]->f=null;
pushup(u);
}
node *getroot(node *u)
{
access(u);
splay(u);
while(u->f!=null)u=u->f;
splay(u);
return u;
}
对于u到v的操作,先把u设为根,再access(v),然后找到u-v上的splay的根,对它进行修改或读取信息。
void query(node *u,node *v)
{
changeroot(u);
splay(v);
node *q=getroot(v);
printf("%d\n",q->maxcost);
}
剩下的慢慢补充