您的位置:首页 > 其它

HDU 4010 动态树LCT学习

2015-09-08 22:14 393 查看
入门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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: