题意:给你个点m条边的无向图,每个节点都有一个整数权值。你的任务是执行一系列操作。操作分为3种。。。
思路:本题一点要逆向来做,正向每次如果删边,复杂度太高。逆向到一定顺序的时候添加一条边更容易。详见算法指南P235。
1 #include<cstdlib> 2 3 struct Node 4 { 5 Node *ch[2]; // 左右子树 6 int r; // 随机优先级 7 int v; // 值 8 int s; // 结点总数 9 Node(int v):v(v) 10 { 11 ch[0] = ch[1] = NULL; 12 r = rand(); 13 s = 1; 14 } 15 int cmp(int x) const 16 { 17 if (x == v) return -1; 18 return x < v ? 0 : 1; 19 } 20 void maintain() 21 { 22 s = 1; 23 if(ch[0] != NULL) s += ch[0]->s; 24 if(ch[1] != NULL) s += ch[1]->s; 25 } 26 }; 27 28 void rotate(Node* &o, int d) 29 { 30 Node* k = o->ch[d^1]; 31 o->ch[d^1] = k->ch[d]; 32 k->ch[d] = o; 33 o->maintain(); 34 k->maintain(); 35 o = k; 36 } 37 38 void insert(Node* &o, int x) 39 { 40 if(o == NULL) o = new Node(x); 41 else 42 { 43 int d = (x < o->v ? 0 : 1); // 不要用cmp函数,因为可能会有相同结点 44 insert(o->ch[d], x); 45 if(o->ch[d]->r > o->r) rotate(o, d^1); 46 } 47 o->maintain(); 48 } 49 50 void remove(Node* &o, int x) 51 { 52 int d = o->cmp(x); 53 int ret = 0; 54 if(d == -1) 55 { 56 Node* u = o; 57 if(o->ch[0] != NULL && o->ch[1] != NULL) 58 { 59 int d2 = (o->ch[0]->r > o->ch[1]->r ? 1 : 0); 60 rotate(o, d2); 61 remove(o->ch[d2], x); 62 } 63 else 64 { 65 if(o->ch[0] == NULL) o = o->ch[1]; 66 else o = o->ch[0]; 67 delete u; 68 } 69 } 70 else 71 remove(o->ch[d], x); 72 if(o != NULL) o->maintain(); 73 } 74 75 #include<cstdio> 76 #include<cstring> 77 #include<vector> 78 using namespace std; 79 80 const int maxc = 500000 + 10; 81 struct Command 82 { 83 char type; 84 int x, p; // 根据type, p代表k或者v 85 } commands[maxc]; 86 87 const int maxn = 20000 + 10; 88 const int maxm = 60000 + 10; 89 int n, m, weight[maxn], from[maxm], to[maxm], removed[maxm]; 90 91 // 并查集相关 92 int pa[maxn]; 93 int findset(int x) 94 { 95 return pa[x] != x ? pa[x] = findset(pa[x]) : x; 96 } 97 98 // 名次树相关 99 Node* root[maxn]; // Treap 100 101 int kth(Node* o, int k) // 第k大的值 102 { 103 if(o == NULL || k <= 0 || k > o->s) return 0; 104 int s = (o->ch[1] == NULL ? 0 : o->ch[1]->s); 105 if(k == s+1) return o->v; 106 else if(k <= s) return kth(o->ch[1], k); 107 else return kth(o->ch[0], k-s-1); 108 } 109 110 void mergeto(Node* &src, Node* &dest) 111 { 112 if(src->ch[0] != NULL) mergeto(src->ch[0], dest); 113 if(src->ch[1] != NULL) mergeto(src->ch[1], dest); 114 insert(dest, src->v); 115 delete src; 116 src = NULL; 117 } 118 119 void removetree(Node* &x) 120 { 121 if(x->ch[0] != NULL) removetree(x->ch[0]); 122 if(x->ch[1] != NULL) removetree(x->ch[1]); 123 delete x; 124 x = NULL; 125 } 126 127 // 主程序相关 128 void add_edge(int x) 129 { 130 int u = findset(from[x]), v = findset(to[x]); 131 if(u != v) 132 { 133 if(root[u]->s < root[v]->s) 134 { 135 pa[u] = v; 136 mergeto(root[u], root[v]); 137 } 138 else 139 { 140 pa[v] = u; 141 mergeto(root[v], root[u]); 142 } 143 } 144 } 145 146 int query_cnt; 147 long long query_tot; 148 void query(int x, int k) 149 { 150 query_cnt++; 151 query_tot += kth(root[findset(x)], k); 152 } 153 154 void change_weight(int x, int v) 155 { 156 int u = findset(x); 157 remove(root[u], weight[x]); 158 insert(root[u], v); 159 weight[x] = v; 160 } 161 162 int main() 163 { 164 int kase = 0; 165 while(scanf("%d%d", &n, &m) == 2 && n) 166 { 167 for(int i = 1; i <= n; i++) scanf("%d", &weight[i]); 168 for(int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]); 169 memset(removed, 0, sizeof(removed)); 170 171 // 读命令 172 int c = 0; 173 for(;;) 174 { 175 char type; 176 int x, p = 0, v = 0; 177 scanf(" %c", &type); 178 if(type == ‘E‘) break; 179 scanf("%d", &x); 180 if(type == ‘D‘) removed[x] = 1; 181 if(type == ‘Q‘) scanf("%d", &p); 182 if(type == ‘C‘) 183 { 184 scanf("%d", &v); 185 p = weight[x]; 186 weight[x] = v; 187 } 188 commands[c++] = (Command) 189 { 190 type, x, p 191 }; 192 } 193 194 // 最终的图 195 for(int i = 1; i <= n; i++) 196 { 197 pa[i] = i; 198 if(root[i] != NULL) removetree(root[i]); 199 root[i] = new Node(weight[i]); 200 } 201 for(int i = 1; i <= m; i++) if(!removed[i]) add_edge(i); 202 203 // 反向操作 204 query_tot = query_cnt = 0; 205 for(int i = c-1; i >= 0; i--) 206 { 207 if(commands[i].type == ‘D‘) add_edge(commands[i].x); 208 if(commands[i].type == ‘Q‘) query(commands[i].x, commands[i].p); 209 if(commands[i].type == ‘C‘) change_weight(commands[i].x, commands[i].p); 210 } 211 printf("Case %d: %.6lf\n", ++kase, query_tot / (double)query_cnt); 212 } 213 return 0; 214 }
时间: 2024-10-11 17:08:54