您的位置:首页 > 其它

COGS 526 又是一道模板题——左偏树

2015-08-18 17:00 381 查看
这不刚刚学会写左偏树嘛,COGS上正好有个左偏树的分类,本来想做第一道,USACO Jan09的安全路径,可是那道题谜一样的题目描述吓到我了,于是就看了下面那一道,就是这道题。相当于又粘了一下模板。

只需要在结构体中加上一个fa,方便给出节点找出树根,再用并查集判断两只猴子是否在一个堆中(就是已经是朋友的都在一个大根堆中,最开始有n个大根堆)就可以。我没仔细想是否可以直接用并查集的树根表示堆的树根,或者只需要用并查集来做(偷个懒嘿嘿)。

每次给出要争吵的猴子a和b,用并查集判断如果他们是朋友输出-1,如果不是,找出a,b在的堆的根A,B,分别合并A,B的左右孩子,再合并一下。之后把A,B的数据更改一下:权值除以2,左右孩子设为0,再插入到堆中即可。最后输出堆顶。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

int n, m, f[100005];

struct node{
int w, lc, rc, h, fa;
}t[100005];

int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}

int merge(int A, int B){
if(!A) return B;
if(!B) return A;
if(t[A].w < t[B].w) swap(A, B);
t[A].rc = merge(t[A].rc, B);
if(t[t[A].lc].h < t[t[A].rc].h) swap(t[A].lc, t[A].rc);
if(t[A].rc) t[A].h = t[A].rc+1;
else t[A].h = 0;
if(t[A].lc) t[t[A].lc].fa = A;
if(t[A].rc) t[t[A].rc].fa = A;
t[A].fa = 0;
return A;
}

int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &t[i].w);
f[i] = i;
}
scanf("%d", &m);
while(m--){
int a, b;
scanf("%d %d", &a, &b);
int fa = find(a), fb = find(b);
if(fa == fb) printf("-1\n");
else{
int A = fa, B = fb, ra, rb, r1, r2, r3;
while(t[A].fa) A = t[A].fa;
while(t[B].fa) B = t[B].fa;
t[A].w /= 2;   t[B].w /= 2;
ra = merge(t[A].lc, t[A].rc);
rb = merge(t[B].lc, t[B].rc);
t[A].lc = t[A].rc = t[B].lc = t[B].rc = 0;
r1 = merge(ra, rb);
r2 = merge(r1, A);
r3 = merge(r2, B);
f[fa] = fb;
printf("%d\n", t[r3].w);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: