思想很好理解,代码很好写
我偷懒想用动态内存,省点代码,结果悲剧了
merge两个左偏树以后内存的维护边的异常混乱,无奈不维护内存了,直接makeNULL();
C++唯一让我不爽的地方就是动态内存的维护太费劲了。
1 #include < iostream >
2 #include < cstring >
3 #include < cstdio >
4 #include < cassert >
5 using namespace std;
6 #define CMP(a, b) ((a) > (b))
7 #define DIST(v) ((v == NULL) ? -1 : (v->dist))
8 // must be careful when clear after merge
9 // because of the pointer could not be NULL
10 // especially when use new
11 template < typename T >
12 class leftist_tree
13 {
14 private :
15 class node
16 {
17 public :
18 T v;
19 int dist;
20 node * rr, * ll;
21 node(){rr = ll = NULL; dist = 0 ;}
22 node(T v){ this -> v = v; rr = ll = NULL;dist = 0 ;}
23 };
24 node * root;
25 int s;
26 node * merge(node * & left, node * & right)
27 {
28 if (left == NULL) return right;
29 if (right == NULL) return left;
30 if (CMP(right -> v, left -> v)) swap(left, right);
31 left -> rr = merge(left -> rr, right);
32 if (DIST(left -> rr) > DIST(left -> ll)) swap(left -> ll, left -> rr);
33 left -> dist = DIST(left -> rr) + 1 ;
34 return left;
35 }
36 void clear(node * root)
37 {
38 if (root == NULL) return ;
39 clear(root -> ll);
40 clear(root -> rr);
41 delete root;
42 root = NULL;
43 }
44 public :
45 leftist_tree(){root = NULL;s = 0 ;}
46 ~ leftist_tree(){clear(root);}
47 void push(T v)
48 {
49 node * newNode = new node(v);
50 root = merge(newNode, root);
51 s ++ ;
52 }
53 void clear(){clear(root);}
54 int size(){ return this -> s;}
55 T top(){ return root -> v;}
56 void pop()
57 {
58 node * tmp = root;
59 root = merge(root -> ll, root -> rr);
60 delete tmp;
61 s -- ;
62 }
63 void merge(leftist_tree < T >& tree)
64 {
65 this -> root = merge(root, tree.root);
66 s += tree.s;
67 tree.root = NULL;
68 }
69 void makeNULL(){root = NULL;}
70 };
71
72 const int N = 100001 ;
73 leftist_tree < int > tree[N];
74 int father[N], rank[N];
75 int find_set( int x)
76 {
77 return father[x] = father[x] == x ? x :find_set(father[x]);
78 }
79 bool union_set( int x, int y)
80 {
81 if (x != y)
82 {
83 if (rank[x] < rank[y]) father[x] = y;
84 else
85 {
86 rank[x] += rank[x] == rank[y];
87 father[y] = x;
88 }
89 return false ;
90 }
91 return true ;
92 }
93 bool link_set( int x, int y)
94 {
95 return union_set(find_set(x), find_set(y));
96 }
97
98 void initialize( int n)
99 {
100 for ( int i = 1 ;i <= n;i ++ )
101 {
102 rank[i] = 0 ;
103 father[i] = i;
104 }
105 }
106 int main()
107 {
108 int n, m, s, a, b;
109 while (scanf( " %d " , & n) == 1 )
110 {
111 for ( int i = 1 ;i <= n;i ++ )
112 {
113 tree[i].clear();
114 scanf( " %d " , & s);
115 tree[i].push(s);
116 }
117 initialize(n);
118 scanf( " %d " , & m);
119 while (m -- )
120 {
121 scanf( " %d %d " , & a, & b);
122 int fa = find_set(a), fb = find_set(b);
123 if (fa == fb) puts( " -1 " );
124 else
125 {
126 link_set(fa, fb);
127 int va = tree[fa].top();
128 tree[fa].pop();tree[fa].push(va / 2 );
129 int vb = tree[fb].top();
130 tree[fb].pop();tree[fb].push(vb / 2 );
131 if (fa == find_set(fa))
132 tree[fa].merge(tree[fb]);
133 else
134 tree[fb].merge(tree[fa]);
135 printf( " %d\n " , tree[find_set(fa)].top());
136 }
137 }
138 }
139 return 0 ;
140 }
赤裸裸的左偏树合并操作。第一次写比较搓……
05年论文里的题目没有看懂,太弱了,还要继续加油呀!省赛一等奖,四省赛一等奖!