hdu 3726 Graph and Queries (Treap应用,名次树)
2014-10-04 02:40
281 查看
名次树还是比较容易理解的。这道题经典主要在于可以用并查集来维护连通的点,并且使用离线算法,倒过来处理,把分开变成了合并!!
PS: 虽然这道题不存在这个问题。但有时,可能remove不存在的值,如果不先find就可能会爆栈。。(因为一直找不到->一直找)
PS: 虽然这道题不存在这个问题。但有时,可能remove不存在的值,如果不先find就可能会爆栈。。(因为一直找不到->一直找)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <queue> #include <stack> #include <cassert> #include <algorithm> #include <cmath> #include <set> #include <limits> using namespace std; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i)) #define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i)) #define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i)) #define MAXN 100 #define MAXM 10000 #define MOD 10000007 #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 typedef long long LL; const double maxdouble = numeric_limits<double>::max(); const double eps = 1e-10; const int INF = 0x7FFFFFFF; //Treap // 每个节点有两个属性:rank和value // 按照rank 这是一个堆 // 按照value 是一颗排序二叉树 //节点定义 typedef struct Node { Node *ch[2]; int r; // rank int v; // value int s; // size 名次树中子树结点个数 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; } }TreapNode; class Treap { public: void insert(TreapNode* &o, int x) { if (o == NULL) { //o = new TreapNode(); //o->ch[0] = o->ch[1] = NULL; //o->v = x; //o->r = rand(); //o->s = 1; make_node(o, x); } else { //int d = o->cmp(x); int d = o->v > x ? 0 : 1; // 名次数中的v可能重复 insert(o->ch[d], x); if (o->ch[d]->r > o->r) rotate(o, d^1); } o->maintain(); } // 两棵子树:先把优先级较高的旋转到根 // 然后在另一棵子树中递归删除x void remove(TreapNode* &o, int x) { int d = o->cmp(x); if (d == -1) { TreapNode* u = o; if (o->ch[0] == NULL) { o = o->ch[1]; delete u; } else if (o->ch[1] == NULL) { o = o->ch[0]; delete u; } else { if (o->ch[0]->r > o->ch[1]->r) { d = 1; } else { d = 0; } rotate(o, d); remove(o->ch[d], x); } } else { remove(o->ch[d], x); } if(o != NULL) o->maintain(); } // 求第k大的值 0表示不存在 int kth(TreapNode* 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 make_node(TreapNode* &o, int x) { o = new TreapNode(); o->ch[0] = o->ch[1] = NULL; o->r = rand(); o->s = 1; o->v = x; } void destroy(TreapNode* &o) { if (o->ch[0] != NULL) destroy(o->ch[0]); if (o->ch[1] != NULL) destroy(o->ch[1]); delete o; o = NULL; } private: // 旋转操作:d=0左转 d=1右转 void rotate(TreapNode* &o, int d) { TreapNode* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o; // o成为k的子树 而k的另一个子树没发生变化 // 所以先维护o 在维护k o->maintain(); k->maintain(); o = k; } }; struct Command{ char c; int param1; int param2; }; const int maxn = 20000; const int maxm = 60000; const int maxc = 600000; int n, m; Command cmds[maxc+5]; int from[maxm + 5]; int to[maxm + 5]; bool removed[maxm + 5]; int w[maxn + 5]; //Treap Treap treap; TreapNode* root[maxn + 5]; // Union-find int pa[maxn + 1]; int findset(int x) { return pa[x] == x ? x : pa[x] = findset(pa[x]); } void mergeto(TreapNode* &src, TreapNode* &dst) { if (src->ch[0] != NULL) mergeto(src->ch[0], dst); if (src->ch[1] != NULL) mergeto(src->ch[1], dst); treap.insert(dst, src->v); delete src; src = NULL; } int main() { //freopen("input.in", "r", stdin); char ch; int cases = 0, x, y; while(scanf("%d%d",&n,&m) == 2 && (n || m)) { memset(removed, false, sizeof(removed)); REP(i, 1, n) scanf("%d", &w[i]); REP(i, 1, m) scanf("%d%d",&from[i], &to[i]); int cnt = 0; for(;;) { for(;;) { scanf("%c",&ch); if (isalpha(ch)) break; } cmds[cnt].c = ch; if (ch == 'E') break; if (ch == 'D') { scanf("%d",&x); removed[x] = true; cmds[cnt].param1 = x; } else if(ch == 'Q') { scanf("%d%d",&x, &y); cmds[cnt].param1 = x; cmds[cnt].param2 = y; } else { scanf("%d%d",&x, &y); cmds[cnt].param1 = x; cmds[cnt].param2 = w[x]; w[x] = y; } ++cnt; } REP(i, 1, n) treap.make_node(root[i], w[i]); REP(i, 1, n) pa[i] = i; REP(i, 1, m) if (!removed[i]) { x = findset(from[i]); y = findset(to[i]); if (x != y) { if (root[x]->s < root[y]->s) { mergeto(root[x], root[y]); pa[x] = y; } else { mergeto(root[y], root[x]); pa[y] = x; } } } LL sum = 0; int query_cnt = 0; UREP(i, cnt-1, 0) { if (cmds[i].c == 'D') { int e = cmds[i].param1; int x = findset(from[e]), y = findset(to[e]); if (x != y) { if (root[x]->s < root[y]->s) { mergeto(root[x], root[y]); pa[x] = y; } else { mergeto(root[y], root[x]); pa[y] = x; } } } else if (cmds[i].c == 'C') { int x = cmds[i].param1; int v = cmds[i].param2; int fa = findset(x); treap.remove(root[fa], w[x]); treap.insert(root[fa], v); w[x] = v; } else { int x = findset(cmds[i].param1); int k = cmds[i].param2; ++query_cnt; sum += treap.kth(root[x], k); } } printf("Case %d: %.6f\n",++cases, sum/(double)query_cnt); REP(i, 1, n) if (root[i] != NULL) treap.destroy(root[i]); } return 0; }使用真实指针null代替NULL的版本
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <queue> #include <stack> #include <cassert> #include <algorithm> #include <cmath> #include <set> #include <limits> using namespace std; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i)) #define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i)) #define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i)) #define MAXN 100 #define MAXM 10000 #define MOD 10000007 #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 typedef long long LL; const double maxdouble = numeric_limits<double>::max(); const double eps = 1e-10; const int INF = 0x7FFFFFFF; //Treap // 每个节点有两个属性:rank和value // 按照rank 这是一个堆 // 按照value 是一颗排序二叉树 //节点定义 typedef struct Node { Node *ch[2]; int r; // rank int v; // value int s; // size 名次树中子树结点个数 int cmp(int x) const { if (x == v) return -1; return x < v ? 0 : 1; } void maintain() { s = ch[0]->s + ch[1]->s + 1; } }TreapNode; class Treap { public: Treap() { null = new TreapNode(); null->ch[0] = null->ch[1] = null; null->s = 0;} ~Treap(){delete null;} void insert(TreapNode* &o, int x) { if (o == null) { //o = new TreapNode(); //o->ch[0] = o->ch[1] = null; //o->v = x; //o->r = rand(); //o->s = 1; make_node(o, x); } else { //int d = o->cmp(x); int d = o->v > x ? 0 : 1; // 名次数中的v可能重复 insert(o->ch[d], x); if (o->ch[d]->r > o->r) rotate(o, d^1); } o->maintain(); } // 两棵子树:先把优先级较高的旋转到根 // 然后在另一棵子树中递归删除x void remove(TreapNode* &o, int x) { int d = o->cmp(x); if (d == -1) { TreapNode* u = o; if (o->ch[0] == null) { o = o->ch[1]; delete u; } else if (o->ch[1] == null) { o = o->ch[0]; delete u; } else { if (o->ch[0]->r > o->ch[1]->r) { d = 1; } else { d = 0; } rotate(o, d); remove(o->ch[d], x); } } else { remove(o->ch[d], x); } if(o != null) o->maintain(); } // 求第k大的值 0表示不存在 int kth(TreapNode* 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 make_node(TreapNode* &o, int x) { o = new TreapNode(); o->ch[0] = o->ch[1] = null; o->r = rand(); o->s = 1; o->v = x; } void destroy(TreapNode* &o) { if (o == null) return; if (o->ch[0] != null) destroy(o->ch[0]); if (o->ch[1] != null) destroy(o->ch[1]); delete o; o = null; } TreapNode* null; private: // 旋转操作:d=0左转 d=1右转 void rotate(TreapNode* &o, int d) { TreapNode* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o; // o成为k的子树 而k的另一个子树没发生变化 // 所以先维护o 在维护k o->maintain(); k->maintain(); o = k; } }; struct Command{ char c; int param1; int param2; }; const int maxn = 20000; const int maxm = 60000; const int maxc = 600000; int n, m; Command cmds[maxc+5]; int from[maxm + 5]; int to[maxm + 5]; bool removed[maxm + 5]; int w[maxn + 5]; //Treap Treap treap; TreapNode* root[maxn + 5]; // Union-find int pa[maxn + 1]; int findset(int x) { return pa[x] == x ? x : pa[x] = findset(pa[x]); } void mergeto(TreapNode* &src, TreapNode* &dst) { if (src->ch[0] != treap.null) mergeto(src->ch[0], dst); if (src->ch[1] != treap.null) mergeto(src->ch[1], dst); treap.insert(dst, src->v); delete src; src = treap.null; } int main() { freopen("input.in", "r", stdin); char ch; int cases = 0, x, y; while(scanf("%d%d",&n,&m) == 2 && (n || m)) { memset(removed, false, sizeof(removed)); REP(i, 1, n) scanf("%d", &w[i]); REP(i, 1, m) scanf("%d%d",&from[i], &to[i]); int cnt = 0; for(;;) { for(;;) { scanf("%c",&ch); if (isalpha(ch)) break; } cmds[cnt].c = ch; if (ch == 'E') break; if (ch == 'D') { scanf("%d",&x); removed[x] = true; cmds[cnt].param1 = x; } else if(ch == 'Q') { scanf("%d%d",&x, &y); cmds[cnt].param1 = x; cmds[cnt].param2 = y; } else { scanf("%d%d",&x, &y); cmds[cnt].param1 = x; cmds[cnt].param2 = w[x]; w[x] = y; } ++cnt; } REP(i, 1, n) treap.make_node(root[i], w[i]); REP(i, 1, n) pa[i] = i; REP(i, 1, m) if (!removed[i]) { x = findset(from[i]); y = findset(to[i]); if (x != y) { if (root[x]->s < root[y]->s) { mergeto(root[x], root[y]); pa[x] = y; } else { mergeto(root[y], root[x]); pa[y] = x; } } } LL sum = 0; int query_cnt = 0; UREP(i, cnt-1, 0) { if (cmds[i].c == 'D') { int e = cmds[i].param1; int x = findset(from[e]), y = findset(to[e]); if (x != y) { if (root[x]->s < root[y]->s) { mergeto(root[x], root[y]); pa[x] = y; } else { mergeto(root[y], root[x]); pa[y] = x; } } } else if (cmds[i].c == 'C') { int x = cmds[i].param1; int v = cmds[i].param2; int fa = findset(x); treap.remove(root[fa], w[x]); treap.insert(root[fa], v); w[x] = v; } else { int x = findset(cmds[i].param1); int k = cmds[i].param2; ++query_cnt; sum += treap.kth(root[x], k); } } printf("Case %d: %.6f\n",++cases, sum/(double)query_cnt); REP(i, 1, n) treap.destroy(root[i]); } return 0; }
相关文章推荐
- hdu 3726 Graph and Queries 10天津赛区 离线算法+treap维护名次树
- hdu 3726 Graph and Queries 名次树
- hdu 3726 Graph and Queries 名次树
- HDU 3726 Graph and Queries(treap)
- hdu 3726 Graph and Queries , 天津 2010, LA 5031,并查集,Treap,离线处理
- HDU 3726 Graph and Queries Treap
- HDU 3726 Graph and Queries 离线处理 treap + 并查集
- HDU 3726 Graph and Queries (Treap)
- HDU 3276 Graph and Queries [离线+并查集+treap]
- 【HDU】3726 Graph and Queries
- HDU 3726 Graph and Queries (离线处理+splay tree)
- LA 5031 Graph and Queries (离线处理 + Treap树维护名次)
- HDU 3726 Graph and Queries
- Hdu 3726 Graph and Queries(删边,查询第k大,修改点值)
- Hdu 3726 Graph and Queries(并查集+平衡树+启发式合并)
- hdu 3726 Graph and Queries(splay查询第k大,启发式合并,删除操作)
- UVa 1479 (Treap 名次树) Graph and Queries
- HDU 3726 Graph and Queries 平衡树+前向星+并查集+离线操作+逆向思维 数据结构大综合题
- hdu 3726 Graph and Queries
- HDU 3726 Graph and Queries(平衡二叉树)(2010 Asia Tianjin Regional Contest)