UVa 1479 (Treap 名次树) Graph and Queries

这题写起来真累。。

名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少。

所以在这道题中用一棵名次树来维护一个连通分量。

由于图中添边比较方便,用并查集来表示连通分量就好了,但是删边不太容易实现。

所以,先把所有的边删去,然后逆序执行命令。当然,C命令也要发生一些变化,比如说顺序的情况是从a变成b,那么逆序执行的话应该就是从b变成a。

最后两棵树的合并就是启发式合并,把节点数少的数并到节点数多的数里去。

  1 #include <cstdio>

  2 #include <cstring>

  3 #include <cstdlib>

  4 using namespace std;

  5 

  6 struct Node

  7 {

  8     Node* ch[2];

  9     int r, v, s;

 10     Node(int v):v(v) { ch[0] = ch[1] = NULL; s = 1; r = rand(); }

 11     int cmp(int x)

 12     {

 13         if(x == v) return -1;

 14         return x < v ? 0 : 1;

 15     }

 16     void maintain()

 17     {

 18         s = 1;

 19         if(ch[0] != NULL) s += ch[0]->s;

 20         if(ch[1] != NULL) s += ch[1]->s;

 21     }

 22 };

 23 

 24 void rotate(Node* &o, int d)

 25 {

 26     Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;

 27     o->maintain(); k->maintain(); o = k;

 28 }

 29 

 30 void insert(Node* &o, int x)

 31 {

 32     if(o == NULL) o = new Node(x);

 33     else

 34     {

 35         int d = x < o->v ? 0 : 1;

 36         insert(o->ch[d], x); if(o->ch[d]->r > o->r) rotate(o, d^1);

 37     }

 38     o->maintain();

 39 }

 40 

 41 void remove(Node* &o, int x)

 42 {

 43     int d = o->cmp(x);

 44     if(d == -1)

 45     {

 46         if(o->ch[0] == NULL) o = o->ch[1];

 47         else if(o->ch[1] == NULL) o = o->ch[0];

 48         else

 49         {

 50             int d2 = o->ch[0]->r < o->ch[1]->r ? 0 : 1;

 51             rotate(o, d2); remove(o->ch[d2], x);

 52         }

 53     }

 54     else remove(o->ch[d], x);

 55     if(o != NULL) o->maintain();

 56 }

 57 

 58 const int maxc = 500000 + 10;

 59 struct Command

 60 {

 61     char type;

 62     int x, p;

 63 }cmd[maxc];

 64 

 65 const int maxn = 20000 + 10;

 66 const int maxm = 60000 + 10;

 67 

 68 int weight[maxn], from[maxm], to[maxm];

 69 bool removed[maxm];

 70 int n, m, query_cnt;

 71 long long query_tot;

 72 

 73 int pa[maxn];

 74 int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }

 75 

 76 Node* root[maxn];

 77 

 78 int kth(Node* o, int k)

 79 {

 80     if(o == NULL || k <= 0 || k > o->s) return 0;

 81     int s = o->ch[1] == NULL ? 0 : o->ch[1]->s;

 82     if(k == s + 1) return o->v;

 83     if(k <= s) return kth(o->ch[1], k);

 84     return kth(o->ch[0], k - s - 1);

 85 }

 86 

 87 void MergeTo(Node* &src, Node* &dest)

 88 {

 89     if(src->ch[0] != NULL) MergeTo(src->ch[0], dest);

 90     if(src->ch[1] != NULL) MergeTo(src->ch[1], dest);

 91     insert(dest, src->v);

 92     delete src;

 93     src = NULL;

 94 }

 95 

 96 void RemoveTree(Node* &o)

 97 {

 98     if(o->ch[0] != NULL) RemoveTree(o->ch[0]);

 99     if(o->ch[1] != NULL) RemoveTree(o->ch[1]);

100     delete o;

101     o = NULL;

102 }

103 

104 void AddEdge(int x)

105 {

106     int u = findset(from[x]);

107     int v = findset(to[x]);

108     if(u != v)

109     {

110         if(root[u]->s < root[v]->s) { pa[u] = v; MergeTo(root[u], root[v]); }

111         else { pa[v] = u; MergeTo(root[v], root[u]); }

112     }

113 }

114 

115 void Query(int x, int k)

116 {

117     query_cnt++;

118     query_tot += kth(root[findset(x)], k);

119 }

120 

121 void ChangeWeight(int x, int v)

122 {

123     int u = findset(x);

124     remove(root[u], weight[x]);

125     insert(root[u], v);

126     weight[x] = v;

127 }

128 

129 int main()

130 {

131     //freopen("in.txt", "r", stdin);

132 

133     int kase = 0;

134     while(scanf("%d%d", &n, &m) == 2 && n)

135     {

136         for(int i = 1; i <= n; i++) scanf("%d", &weight[i]);

137         for(int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]);

138         memset(removed, false, sizeof(removed));

139 

140         int c = 0;

141         for(;;)

142         {

143             char type[5]; scanf("%s", type);

144             if(type[0] == 'E') break;

145             int x, p = 0, v = 0;

146             scanf("%d", &x);

147             if(type[0] == 'D') removed[x] = true;

148             if(type[0] == 'Q') scanf("%d", &p);

149             if(type[0] == 'C')

150             {

151                 scanf("%d", &v);

152                 p = weight[x];

153                 weight[x] = v;

154             }

155             cmd[c++] = (Command) { type[0], x, p };

156         }

157 

158         for(int i = 1; i <= n; i++)

159         {

160             pa[i] = i; if(root[i] != NULL) RemoveTree(root[i]);

161             root[i] = new Node(weight[i]);

162         }

163         for(int i = 1; i <= m; i++) if(!removed[i]) AddEdge(i);

164 

165         query_cnt = query_tot = 0;

166         for(int i = c - 1; i >= 0; i--)

167         {

168             char type = cmd[i].type;

169             int x = cmd[i].x, p = cmd[i].p;

170             if(type == 'D') AddEdge(x);

171             if(type == 'Q') Query(x, p);

172             if(type == 'C') ChangeWeight(x, p);

173         }

174         printf("Case %d: %.6f\n", ++kase, query_tot / (double)query_cnt);

175     }

176 

177     return 0;

178 }
代码君

 

你可能感兴趣的:(Graph)