[Treap] LA5031 Graph and Queries
2017-08-24 19:31
183 查看
题意&思路
其实蓝书上面已经说的很清楚了,就是给一个图,每一个点都有一个值,然后不断地删除某条边,修改某个点的值,然后查某个联通块里的第k大。做法就是静态处理,反过来做。因为如果是删除的话,有可能会导致一棵Treap要分裂,然后这显然很不好处理,相比起来往一棵Treap当中插入另一个显然更好,那当然是反过来做更好。
那么用并查集来确定某个点所处于的块。
合并的时候启发式合并,为什么说是启发式合并呢?
首先是把小的往大的里面插入,这样插入就会少一点。然后先插入大的,可以让被插入的Treap深度增加的时候,后面插入的值的深度不会太大,这样可以加快速度。
具体做法看蓝书都很懂了,但是写代码的时候还是错漏百出……书上的例题留到了后面来做,主要是因为折是一个不是很裸的题,先做模板题练练手会更好。
代码
#include <ctime> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; struct Node { Node *ch[2]; int r; int v; int s; Node() {} Node(int w) { r = 0; ch[0] = ch[1] = NULL; v = w; s = 1; } int cmp(int x) const { if(x == v) return -1; return x < v ? 0 : 1; } void maintain() { s = 1; if(ch[0] != NULL) { s += ch[0] -> s; } if(ch[1] != NULL) { s += ch[1] -> s; } } }; struct Treap { Node *root; void init() { if(root != NULL) removetree(root); root = NULL; // srand(time(0)); } void removetree(Node* &x) { // 释放内存 if(x -> ch[0] != NULL) { removetree(x -> ch[0]); } if(x -> ch[1] != NULL) { removetree(x -> ch[1]); } delete x; x = NULL; } void rotate(Node* &o, int d) { Node* k = o -> ch[d ^ 1]; o -> ch[d ^ 1] = k -> ch[d]; k -> ch[d] = o; o -> maintain(); k -> maintain(); o = k; } void insert(Node* &o, int x) { if(o == NULL) { o = new Node(); o -> ch[0] = o -> ch[1] = NULL; o -> v = x; o -> r = rand(); } else { int d = (x v ? 0 : 1); insert(o -> ch[d], x); if(o -> ch[d] -> r > o -> r) { rotate(o, d ^ 1); } } o -> maintain(); } void remove(Node* &o, int x) { int d = o -> cmp(x); if(d == -1) { Node* u = o; if(o -> ch[0] != NULL && o -> ch[1] != NULL) { int d2 = (o -> ch[0] -> r > o -> ch[1] -> r ? 1 : 0); rotate(o, d2); remove(o -> ch[d2], x); } else { if(o -> ch[0] == NULL) { o = o -> ch[1]; } else { o = o -> ch[0]; } delete u; } } else { remove(o -> ch[d], x); } if(o != NULL) { o -> maintain(); } } int find(Node* o, int x) { while(o != NULL) { int d = o -> cmp(x); if(d == -1) return 1; else o = o -> ch[d]; } return 0; } int kth(Node* o, int k) { if(o == NULL || k > o -> s || k <= 0) { return 0; } int s = (o -> ch[1] == NULL ? 0 : o -> ch[1] -> s); if(k == s + 1) { return o -> v; } else { if(k <= s) { return kth(o -> ch[1], k); } else { return kth(o -> ch[0], k - s - 1); } } } void Merge(Node* &o, Treap &b) { // 合并 利用递归启发式合并 if(o == NULL) { return ; } if(o -> ch[0] != NULL) { Merge(o -> ch[0], b); } if(o -> ch[1] != NULL) { Merge(o -> ch[1], b); } b.insert(b.root, o -> v); delete o; o = NULL; } } treap[500010]; const int MAXN = 500010; struct Ques { char o; int x, p; } Q[MAXN]; int a[MAXN]; int u[MAXN], v[MAXN], f[MAXN]; int fa[MAXN]; int _find(int root) { return fa[root] == root ? root : fa[root] = _find(fa[root]); } void AddEdge(int x) { int fu = _find(u[x]); int fv = _find(v[x]); if(fu != fv) { if(treap[fu].root -> s < treap[fv].root -> s) { fa[fu] = fv; treap[fu].Merge(treap[fu].root, treap[fv]); } else { fa[fv] = fu; treap[fv].Merge(treap[fv].root, treap[fu]); } } } int Case = 0; void solve(int n, int m) { for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } for(int i = 1; i <= m; ++i) { scanf("%d%d", &u[i], &v[i]); } memset(f, 0, sizeof f); int cnt = 0; for(;;) { ++cnt; scanf(" %c", &Q[cnt].o); if(Q[cnt].o == 'E') { --cnt; break; } scanf("%d", &Q[cnt].x); if(Q[cnt].o == 'D') { f[Q[cnt].x] = 1; } if(Q[cnt].o == 'Q') { scanf("%d", &Q[cnt].p); } if(Q[cnt].o == 'C') { int y; scanf("%d", &y); Q[cnt].p = a[Q[cnt].x]; a[Q[cnt].x] = y; } } for(int i = 1; i <= n; ++i) { fa[i] = i; treap[i].init(); treap[i].root = new Node(a[i]); } for(int i = 1; i <= m; ++i) { if(!f[i]) { AddEdge(i); } } double tot = 0; int q_cnt = 0; for(int i = cnt; i > 0; --i) { if(Q[i].o == 'D') { AddEdge(Q[i].x); } if(Q[i].o == 'Q') { q_cnt++; int u = _find(Q[i].x); tot += treap[u].kth(treap[u].root, Q[i].p); } if(Q[i].o == 'C') { int fu = _find(Q[i].x); treap[fu].remove(treap[fu].root, a[Q[i].x]); treap[fu].insert(treap[fu].root, Q[i].p); a[Q[i].x] = Q[i].p; } } printf("Case %d: %.6lf\n", ++Case, tot / q_cnt); } int main(void) { // srand(time(0)); int n, m; while(~scanf("%d%d", &n, &m) && n) { solve(n, m); } return 0; }
相关文章推荐
- LA5031 Graph and Queries (Treap模版)
- 【treap tree】 HDOJ 3726 && LA 5031 && UVA 1479 Graph and Queries
- 【UVALive】5031 Graph and Queries treap实现名次树
- HDU 3726 Graph and Queries 离线处理 treap + 并查集
- UVAlive 5031 Graph and Queries(treap)
- UVALive 5031 Graph and Queries(离线,treap)
- Uva 5031 Graph and Queries(Treap)
- HDU 3726 Graph and Queries (Treap)
- HDU 3276 Graph and Queries [离线+并查集+treap]
- UVA 1479 - Graph and Queries(Treap)
- HDU 3726 Graph and Queries(treap)
- UVA 1479 Graph and Queries(Treap:名次树+并查集)
- hdu 3726 Graph and Queries (Treap应用,名次树)
- hdu 3726 Graph and Queries 10天津赛区 离线算法+treap维护名次树
- hdu 3726 Graph and Queries , 天津 2010, LA 5031,并查集,Treap,离线处理
- uva live 5031 Graph and Queries(Treap x 并查集)
- LA 5031 Graph and Queries (【名次树(treap)】+【并查集】+【离线算法】)
- UVA 1479 Graph and Queries (Treap)
- LA 5031 Graph and Queries Treap
- UvaLive 5031 Graph and Queries(Treap+并查集)