HDU 4010 动态树LCT学习
入门LCT的题目,这几天把LCT学习了一下,上手真是好难。这是写的LCT的第一道题,改掉了BUG以后交上去,PE,加了一行空格以后就过了,真是太开心了!!!
写一点刚开始学习的一点感想,等我把题目补完了再来做一个小结。
刚开始看http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 这篇论文的时候真是感觉好烦,看了好几遍以后感觉写得确实太优秀了!!!
LCT也可以说是基于树链剖分的数据结构,树链剖分树按照轻重链剖分,而LCT则是任意的(说是任意的其实也是确定的)。树链剖分是把链扔到树上面进行操作(当然点权也一样,其实对于有根树上的边权也就是点权)。做树链剖分是很关键的就是把无根树转化成有根树。所有树链剖分不支持Link,Cut操作。
LCT除了一个树链剖分,就是一个Splay树来维护一个森林。LCT核心操作是Access(v),即把v点到根的点建一棵Splay树,很难想象这个过程是一个纯暴力过程!!!我们要找对应的u,v的LCA路径的话,只需要Access(u),然后Splay(u),把u点变为根,然后再Access(v),这样子就建立了一个u,v之间的lca的Splay树。Link,Cut操作看代码就都很明白了。
因为LCT维护的是一个Splay森林,所以我们需要知道每棵树的树根(即当前节点是不是树根),我们用一个rt[MAXN]数组来表示,这是看bin神博客学习的。这个时候需要注意的就是Splay树操作的核心:旋转。除了更新节点之间的链接之外,还需要更新rt数组。当然Access操作也需要更新rt数组。
下面先把我的代码附上:
#include <cstring> #include <cmath> #include <algorithm> #include <cstdio> #include <vector> #define LL long long #define INF 0x3fffffff #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) #define MAXN 330000 using namespace std; int n,q; vector <int> mat[MAXN]; struct LCT{ int pre[MAXN],ch[MAXN][2],key[MAXN]; int maxx[MAXN],add[MAXN],flip[MAXN]; bool rt[MAXN]; void Update_Add(int x,int w){ if(!x) return; maxx[x] += w; add[x] += w; key[x] += w; } void Update_Flip(int x){ if(!x) return; swap(ch[x][0],ch[x][1]); flip[x] ^= 1; } void Init(){ memset(ch,0,sizeof(ch)); memset(flip,0,sizeof(flip)); memset(add,0,sizeof(add)); memset(rt,true,sizeof(rt)); maxx[0] = -INF; FOR(i,1,n+1) maxx[i] = key[i]; } void PushUp(int x){ maxx[x] = max(max(maxx[ch[x][1]],maxx[ch[x][0]]),key[x]); } void PushDown(int x){ if(add[x]){ if(ch[x][0]) Update_Add(ch[x][0],add[x]); if(ch[x][1]) Update_Add(ch[x][1],add[x]); add[x] = 0; } if(flip[x]){ if(ch[x][0]) Update_Flip(ch[x][0]); if(ch[x][1]) Update_Flip(ch[x][1]); flip[x] = 0; } } void Rotate(int x,int kind){ int y = pre[x]; PushDown(y); PushDown(x); ch[y][!kind] = ch[x][kind]; if(ch[x][kind]) pre[ch[x][kind]] = y; if(rt[y]){ rt[x] = true; rt[y] = false; } else{ if(ch[pre[y]][1] == y) ch[pre[y]][1] = x; if(ch[pre[y]][0] == y) ch[pre[y]][0] = x; } pre[x] = pre[y]; pre[y] = x; ch[x][kind] = y; PushUp(y); } void Splay(int x){ PushDown(x); while(!rt[x]){ int y = pre[x]; int z = pre[y]; PushDown(z); PushDown(y); PushDown(x); if(rt[y]){ Rotate(x,ch[y][0] == x); } else{ int kind = ch[z][0] == y; if(ch[y][kind] == x){ Rotate(x,!kind); Rotate(x,kind); } else{ Rotate(y,kind); Rotate(x,kind); } } } PushUp(x); } void Access(int x){ int fa = 0; for(;x;x = pre[fa = x]){ Splay(x); rt[ch[x][1]] = true; rt[ch[x][1] = fa] = false; PushUp(x); } } <span style="white-space:pre"> </span>
//找到x这棵子树的树根 int GetRoot(int x){ Access(x); Splay(x); while(ch[x][0]) x = ch[x][0]; return x; }
//把x节点变成当前Splay树的树根
void MakeRoot(int x){ Access(x); Splay(x); Update_Flip(x); } bool Link(int u,int v){ if(GetRoot(u) == GetRoot(v)) return false; MakeRoot(u); pre[u] = v; Access(u); return true; } bool Cut(int u,int v){ if(u == v || GetRoot(u) != GetRoot(v)) return false; MakeRoot(u); Access(v); Splay(v); if(ch[v][0]) pre[ch[v][0]] = pre[v],rt[ch[v][0]] = true; pre[v] = 0; ch[v][0] = 0; PushUp(v); return true; } bool Add(int u,int v,int w){ int t1 = GetRoot(u); int t2 = GetRoot(v); if(t1 != t2) return false; MakeRoot(u); Access(v); Splay(v); Update_Add(v,w); return true; } int Query(int u,int v){ int t1 = GetRoot(u); int t2 = GetRoot(v); if(t1 != t2) return -1; MakeRoot(u); Access(v); Splay(v); return maxx[v]; } }lct; void dfs(int u,int fa){ lct.pre[u] = fa; for(int i = 0;i < mat[u].size();i ++){ int v = mat[u][i]; if(v == fa) continue; dfs(v,u); } } int main(){ //freopen("test.in","r",stdin); while(~scanf("%d",&n)){ FOR(i,1,n+1) mat[i].clear(); FOR(i,1,n){ int u,v; scanf("%d%d",&u,&v); mat[u].push_back(v); mat[v].push_back(u); } dfs(1,0); FOR(i,1,n+1){ scanf("%d",&lct.key[i]); } lct.Init(); scanf("%d",&q); while(q--){ int op; scanf("%d",&op); if(op == 1){ int u,v; scanf("%d%d",&u,&v); if(!lct.Link(u,v)) printf("-1\n"); } else if(op == 2){ int u,v; scanf("%d%d",&u,&v); if(!lct.Cut(u,v)) printf("-1\n"); } else if(op == 3){ int w,u,v; scanf("%d%d%d",&w,&u,&v); if(!lct.Add(u,v,w)) printf("-1\n"); } else{ int u,v; scanf("%d%d",&u,&v); printf("%d\n",lct.Query(u,v)); } } printf("\n"); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。