UvaLive 5031 Graph and Queries(Treap+并查集)

来源:互联网 发布:java培训多少钱 编辑:程序博客网 时间:2024/05/22 14:14

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3032

思路:

1.三种操作:删除编号x的边;计算与结点x连通的点中,第k大权值;修改结点x的权值为c。

2.离线操作,按命令相反的顺序进行(先删除所有要删除的边,修改所有权值)。则操作变为加边和修改点的权值。

3.对于每个点建立一棵名次树。加边可通过并查集维护,对于边u-v,若点u与点v已连通则忽略,否则将点u与点v对应树合并:设u对应T1,点数为n1;v对应T2,点数为n2,若n1<n2,则将T1合并到T2,否则将T2合并到T1(即启发式合并,合并对应将一棵树所有点插入到另一棵树中)。查询操作对应名次树中求第k大值。修改时,记录每个点上一次修改时的值,则每次修改对应从树中删除当前值,然后插入该点的上一个值。

#include<ctime>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define debugusing namespace std;struct Node{Node* ch[2];int r, v, s;Node(int v) :v(v) { ch[0] = ch[1] = NULL; r = rand(); s = 1; }bool operator < (const Node& rhs) const{return r < rhs.r;}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{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(x);}else{int d = (x < o->v ? 0 : 1);insert(o->ch[d], x);if (o->ch[d] > 0) 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] > o->ch[1] ? 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 kth(Node* o, int k){if (o == NULL || k <= 0 || k > o->s) 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 mergeto(Node* &src, Node* &dest){if (src->ch[0] != NULL) mergeto(src->ch[0], dest);if (src->ch[1] != NULL) mergeto(src->ch[1], dest);insert(dest, src->v);delete src;src = NULL;}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;}};const int maxn = 20000 + 50;const int maxm = 60000 + 50;struct Que{int a, b, id;Que(){}Que(int a,int b,int c):a(a),b(b),id(c){}};int n, m;Treap tree;int fa[maxn];Node* root[maxn];Que q[maxn * 30];pair<int, int> e[maxm];int w[maxn], flag[maxm];void init(){memset(w, 0, sizeof(w));memset(flag, 0, sizeof(flag));for (int i = 1; i <= n; i++) fa[i] = i;}int Find(int x){return fa[x] == x ? x : fa[x] = Find(fa[x]);}void addEdge(int x, int y){int u = Find(x),v = Find(y);if (u == v) return;if (root[u]->s < root[v]->s){tree.mergeto(root[u], root[v]);fa[u] = v;}else{tree.mergeto(root[v], root[u]);fa[v] = u;}}int main(){#ifdef  debufreopen("in.txt", "r", stdin);#endif //  debugint cas = 0;srand((int)time(NULL));while (scanf("%d%d", &n, &m) != EOF && (n + m)){init();for (int i = 1; i <= n; i++){scanf("%d", &w[i]);}for (int i = 1; i <= m; i++) scanf("%d%d", &e[i].first, &e[i].second);char ch;int cnt = 0;while (scanf("%c", &ch)){if (ch == 'E') break;if (ch == 'Q'){int u, k;scanf("%d%d", &u, &k);q[++cnt] = Que(u, k, 2);}else if (ch == 'C'){int u, c;scanf("%d%d", &u, &c);int tmp = w[u];w[u] = c;q[++cnt] = Que(u, tmp, 0);}else if (ch == 'D'){int e;scanf("%d", &e);flag[e] = 1;q[++cnt] = Que(e, 0, 1);}}for (int i = 1; i <= n; i++){if (root[i] != NULL) tree.removetree(root[i]);root[i] = new Node(w[i]);}for (int i = 1; i <= m; i++){if (!flag[i]){addEdge(e[i].first, e[i].second);}}int sum = 0;double ans = 0.0;for (int i = cnt; i >=1; i--){if (q[i].id == 2){ans += tree.kth(root[Find(q[i].a)], q[i].b);sum++;}else if (q[i].id == 1){addEdge(e[q[i].a].first, e[q[i].a].second);}else if (q[i].id == 0){int rt = Find(q[i].a);tree.remove(root[rt], w[q[i].a]);tree.insert(root[rt], q[i].b);w[q[i].a] = q[i].b;}}printf("Case %d: %.6f\n", ++cas,ans/sum);}return 0;}



原创粉丝点击