这题用并查集+BST离线解决,编程实现是难点,这题使用动态内存分配比较方便,因为开始可能需要建很多的树,或者自己写一个内存回收类,调试过程很痛苦,RE到MLE再到一直RE,终于AC==。。。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(40010); const int SIGMA_SIZE(82); const int MAXM(500010); const int MAXE(60010); const int MAXH(18); const int INFI((INT_MAX-1) >> 2); const int BASE(131); const int MOD(20071027); const ULL LIM(1000000000000000ull); template<typename T> struct NODE { NODE *ch[2]; int r, s; T key; int cmp(const T &op) const { if(op == key) return -1; return op < key? 0: 1; } void maintain() { s = ch[0]->s+ch[1]->s+1; } }; template<typename T> //内存回收类 struct POOL { typedef NODE<T> ND; ND pool[MAXN]; ND *ind_p; ND *bump[MAXN]; int ind_b; void init() { ind_p = pool; ind_b = 0; } ND *NEW() { return ind_b? bump[--ind_b]: ind_p++; } void FREE(ND *sour) { bump[ind_b++] = sour; } }; template<typename T> struct TREAP { typedef NODE<T> ND; static POOL<T> pool; static ND *NIL; ND *RT; T tkey; void init() { if(NIL == 0) { pool.init(); NIL = pool.NEW(); NIL->ch[0] = NIL->ch[1] = NIL; NIL->s = 0; NIL->r = -1; } RT = NIL; } void rotate(ND *&sour, int f) { ND *tp = sour->ch[f^1]; sour->ch[f^1] = tp->ch[f]; tp->ch[f] = sour; sour->maintain(); tp->maintain(); sour = tp; } void insert( T &value) { tkey = value; insert_(RT); } void insert_(ND *&sour) { if(sour == NIL) { sour = pool.NEW(); sour->ch[0] = sour->ch[1] = NIL; sour->key = tkey; sour->r = rand(); sour->s = 1; } else { int f = (tkey < sour->key? 0: 1); insert_(sour->ch[f]); if(sour->ch[f]->r > sour->r) rotate(sour, f^1); sour->maintain(); } } void remove(const T &value) { tkey = value; remove_(RT); } void remove_(ND *&sour) { int f = sour->cmp(tkey); if(f == -1) { if(sour->ch[0] == NIL) pool.FREE(sour), sour = sour->ch[1]; else if(sour->ch[1] == NIL) pool.FREE(sour), sour = sour->ch[0]; else { int f2 = (sour->ch[0]->r > sour->ch[1]->r? 1: 0); rotate(sour, f2); remove_(sour->ch[f2]); } } else remove_(sour->ch[f]); if(sour != NIL) sour->maintain(); } ND *find(const T &value) { ND *sour = RT; while(sour != NIL) { int f = sour->cmp(value); if(f == -1) break; sour = sour->ch[f]; } return sour; } ND *select(int kth) { ND *sour = RT; int tk; while(sour != NIL && kth != (tk = sour->ch[0]->s+1)) { if(kth < tk) sour = sour->ch[0]; else { kth -= tk; sour = sour->ch[1]; } } return sour; } int rank(const T &value) //此出结果为左界 { ND *sour = RT; int ret = 1; while(sour != NIL) { if(value < sour->key) //如果此处改成<则求出的结果为右界+1 sour = sour->ch[0]; else { ret += sour->ch[0]->s+1; sour = sour->ch[1]; } } return ret; } ND *pre(const T &value) //返回小于value的最大元素的索引,否则返回NIL { tkey = value; return pre_(RT); } ND *pre_(ND *sour) { if(sour == NIL) return NIL; if(tkey <= sour->key) return pre_(sour->ch[0]); else { ND *tp = pre_(sour->ch[1]); return tp == NIL? sour: tp; } } ND *suc(const T &value) //返回大于value的最小元素索引,否则返回NIL { tkey = value; return suc_(RT); } ND *suc_(ND *sour) { if(sour == NIL) return NIL; if(tkey >= sour->key) return suc_(sour->ch[1]); else { ND *tp = suc_(sour->ch[0]); return tp == NIL? sour: tp; } } void merge(ND *&sour) //合并以sour为根节点的子树 { if(sour == NIL) return; merge(sour->ch[0]); merge(sour->ch[1]); insert(sour->key); pool.FREE(sour); sour = NIL; //一定要把sour置为NIL,不然爆栈 } void removetree(ND *&sour) //删除以sour为根节点的子树 { if(sour == NIL) return; removetree(sour->ch[0]); removetree(sour->ch[1]); pool.FREE(sour); sour = NIL; //一定要把sour置为NIL,不然爆栈 } void debug() { printf("/****************************************/\n"); debug_(RT, 0); printf("/****************************************/\n"); } void debug_(ND *sour, int vec) { if(sour == NIL) return; debug_(sour->ch[0], vec+1); for(int i = 0; i < vec; ++i) printf(" "); printf("%d\n", sour->key); debug_(sour->ch[1], vec+1); } }; TREAP<int>::ND *TREAP<int>::NIL = 0; POOL<int> TREAP<int>::pool; struct FIND_SET { int fa[MAXN]; int find(int sour) { return sour == fa[sour]? sour: fa[sour] = find(fa[sour]); } }; struct OP { char type; int op1, op2; }; TREAP<int> trp[20010]; FIND_SET fs; int weight[20010]; OP arr[MAXM]; int cnt; TREAP<int>::ND *NIL = TREAP<int>::NIL; int from[MAXE], to[MAXE]; bool is_remove[MAXE]; void add_edge(int ind) { int u = fs.find(from[ind]), v = fs.find(to[ind]); if(u != v) { if(trp[u].RT->s < trp[v].RT->s) { fs.fa[u] = v; trp[v].merge(trp[u].RT); } else { fs.fa[v] = u; trp[u].merge(trp[v].RT); } } } int main() { int n, m, n_case(0); TREAP<int>::ND *tp; for(int i = 1; i <= 20000; ++i) trp[i].init(); while(scanf("%d%d", &n, &m), n+m) { for(int i = 1; i <= n; ++i) scanf("%d", weight+i); for(int i = 1; i <= m; ++i) scanf("%d%d", from+i, to+i); memset(is_remove, 0, sizeof(is_remove)); cnt = 0; while(scanf(" %c", &arr[cnt].type), arr[cnt].type != 'E') { if(arr[cnt].type == 'D') { scanf("%d", &arr[cnt].op1); is_remove[arr[cnt].op1] = true; } else scanf("%d%d", &arr[cnt].op1, &arr[cnt].op2); if(arr[cnt].type == 'C') swap(arr[cnt].op2, weight[arr[cnt].op1]); ++cnt; } for(int i = 1; i <= n; ++i) { trp[i].removetree(trp[i].RT); trp[i].init(); trp[i].insert(weight[i]); fs.fa[i] = i; } for(int i = 1; i <= m; ++i) if(!is_remove[i]) add_edge(i); double ans = 0; int ansi = 0; int tu; for(int i = cnt-1; i >= 0; --i) { switch(arr[i].type) { case 'D': add_edge(arr[i].op1); break; case 'Q': tu = fs.find(arr[i].op1); if(arr[i].op2 >= 1 && arr[i].op2 <= trp[tu].RT->s) { tp = trp[tu].select(trp[tu].RT->s-arr[i].op2+1); ans += tp->key; } ++ansi; break; case 'C': tu = fs.find(arr[i].op1); trp[tu].remove(weight[arr[i].op1]); trp[tu].insert(arr[i].op2); weight[arr[i].op1] = arr[i].op2; break; } } printf("Case %d: %.6f\n", ++n_case, ans/ansi); } return 0; }