HDU3726---Graph and Queries 离线处理+Treap

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3726

题意:n个点m条边的一张无向图,每个点有一个权值, 有3中操作。

D X 删除第X条边

Q X K 计算与X点相连所有点中第k大的权值

C X V把X的权值改为 V

输出 Q次询问的平均值

大白上的例题, 离线处理,把所有操作 反过来处理,,这样删边变成了 加边,,瞬间好处理多了。。细节也有很多。

  1 #include <set>
  2 #include <map>
  3 #include <cmath>
  4 #include <ctime>
  5 #include <queue>
  6 #include <stack>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 typedef unsigned long long ull;
 16 typedef long long ll;
 17 const int inf = 0x3f3f3f3f;
 18 const double eps = 1e-8;
 19 const int maxn = 2e4+10;
 20 int n, m, val[maxn];
 21 int pa[maxn];
 22 void init()
 23 {
 24     for (int i = 0; i <= n; i++)
 25     {
 26         pa[i] = i;
 27     }
 28 }
 29 int find(int x)
 30 {
 31     return pa[x] = (pa[x] == x ? x : find(pa[x]));
 32 }
 33 struct Node
 34 {
 35     Node* ch[2];
 36     int key, r, siz;
 37     Node (int x)
 38     {
 39         key = x;
 40         siz = 1;
 41         ch[0] = ch[1] = NULL;
 42         r = rand();
 43     }
 44     bool operator < (const Node &rhs)const
 45     {
 46         return r < rhs.r;
 47     }
 48     int cmp(int x)
 49     {
 50         if (x == key)
 51             return -1;
 52         return x < key ? 0 : 1;
 53     }
 54     void maintain()
 55     {
 56         siz = 1;
 57         if (ch[0] != NULL)
 58             siz += ch[0] -> siz;
 59         if (ch[1] != NULL)
 60             siz += ch[1] -> siz;
 61     }
 62 };
 63 void rotate(Node* &root, int d)
 64 {
 65     Node* tmp = root -> ch[d^1];
 66     root -> ch[d^1] = tmp -> ch[d];
 67     tmp -> ch[d] = root;
 68     root -> maintain();
 69     tmp -> maintain();
 70     root = tmp;
 71 }
 72 void insert(Node* &root, int x)
 73 {
 74     if (root == NULL)
 75         root = new Node (x);
 76     else
 77     {
 78         int d = x < root -> key ? 0 : 1;
 79         insert (root ->ch[d], x);
 80         if (root -> ch[d] -> r > root -> r)
 81             rotate(root, d^1);
 82
 83     }
 84     root -> maintain();
 85 }
 86 void dele(Node* &root, int x)
 87 {
 88     int d = root -> cmp(x);
 89     if (d == -1)
 90     {
 91         Node* tmp = root;
 92         if (root -> ch[0] != NULL && root -> ch[1] != NULL)
 93         {
 94             int d1 = (root -> ch[0] -> r > root -> ch[1] -> r ? 0 : 1);
 95             rotate(root, d1^1);
 96             dele(root -> ch[d1^1], x);
 97         }
 98         else
 99         {
100             if (root -> ch[0] == NULL)
101                 root = root -> ch[1];
102             else
103                 root = root -> ch[0];
104             delete tmp;
105         }
106     }
107     else
108         dele(root->ch[d], x);
109     if (root != NULL)
110         root -> maintain();
111 }
112 int Get_kth(Node* root, int k)
113 {
114     if (root == NULL || k <= 0 || root -> siz < k)
115         return 0;
116     int s = root -> ch[1] == NULL ? 0 : root -> ch[1] -> siz;
117     if (s + 1 == k)
118         return root -> key;
119     if (s + 1 > k)
120         return Get_kth(root -> ch[1], k);
121     else
122         return Get_kth(root -> ch[0], k-s-1);
123
124 }
125 Node* root[maxn];
126 void merge_tree(Node* &src, Node* &fa)
127 {
128     if (src -> ch[0] != NULL)
129         merge_tree(src -> ch[0], fa);
130     if (src -> ch[1] != NULL)
131         merge_tree(src -> ch[1], fa);
132     insert(fa, src -> key);
133     delete src;
134     src = NULL;
135 }
136 void remove_tree(Node* &root)
137 {
138     if (root -> ch[0] != NULL)
139         remove_tree(root -> ch[0]);
140     if (root -> ch[1] != NULL)
141         remove_tree(root -> ch[1]);
142     delete root;
143     root = NULL;
144 }
145 struct
146 {
147     int x, y;
148     bool is_del;
149 } e[3 * maxn];
150 struct
151 {
152     int type, x, p;
153 } Q[maxn*25];
154 void add_edge(int idx)
155 {
156     int fx = find(e[idx].x);
157     int fy = find(e[idx].y);
158     if (fx != fy)
159     {
160         if (root[fx] -> siz > root[fy] -> siz)
161         {
162             pa[fy] = fx;
163             merge_tree(root[fy], root[fx]);
164         }
165         else
166         {
167             pa[fx] = fy;
168             merge_tree(root[fx], root[fy]);
169
170         }
171     }
172
173 }
174 int main(void)
175 {
176 #ifndef ONLINE_JUDGE
177     freopen("in.txt","r",stdin);
178 #endif
179     int cas = 1;
180     while (~ scanf ("%d%d",&n, &m))
181     {
182         if (n == 0 && m == 0)
183             break;
184         for (int i = 0; i < n; i++)
185         {
186             scanf ("%d", val + 1 + i);
187         }
188         for (int i = 1; i <= m; i++)
189         {
190             scanf ("%d%d", &e[i].x, &e[i].y);
191             e[i].is_del = false;
192         }
193         char op[5];
194         int tot = 0;
195         while (scanf ("%s",op) && op[0] != ‘E‘)
196         {
197             if (op[0] == ‘D‘)
198             {
199                 scanf ("%d", &Q[tot].x);
200                 Q[tot++].type = 0;
201                 e[Q[tot-1].x].is_del = true;
202             }
203             if (op[0] == ‘Q‘)
204             {
205                 scanf ("%d%d", &Q[tot].x, &Q[tot].p);
206                 Q[tot++].type = 1;
207             }
208             if (op[0] == ‘C‘)
209             {
210                 int v;
211                 scanf ("%d%d", &Q[tot].x, &v);
212                 Q[tot].p = val[Q[tot].x];
213                 val[Q[tot].x] = v;
214                 Q[tot++].type = 2;
215             }
216         }
217         init();
218         for (int i = 0; i < n; i++)
219         {
220             if (root[i+1] != NULL)
221                 remove_tree(root[i+1]);
222             root[i+1] = new Node (val[i+1]);
223         }
224         for (int i = 0; i < m; i++)
225         {
226             if (e[i+1].is_del == false)
227                 add_edge(i+1);
228         }
229         ll ans1 = 0, ans2 = 0;
230         for (int i = tot - 1; i >= 0; i--)
231         {
232             if (Q[i].type == 0)
233             {
234                 add_edge(Q[i].x);
235             }
236             if (Q[i].type == 1)
237             {
238                 ans1 += Get_kth(root[find(Q[i].x)], Q[i].p);
239                 ans2 ++;
240             }
241             if (Q[i].type == 2)
242             {
243                int father = find(Q[i].x);
244                 dele (root[father], val[Q[i].x]);
245                 insert (root[father], Q[i].p);
246                 val[Q[i].x] = Q[i].p;
247             }
248         }
249         printf("Case %d: %.6f\n", cas++, 1.0*ans1 / ans2);
250     }
251     return 0;
252 }
时间: 2024-08-25 10:39:38

HDU3726---Graph and Queries 离线处理+Treap的相关文章

uvalive 5031 Graph and Queries 名次树+Treap

题意:给你个点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

UVaLive 5031 Graph and Queries (Treap)

Graph and Queries Description You are given an undirected graph with N vertexes and M edges. Every vertex in this graph has an integer value assigned to it at the beginning. You’re also given a sequence of operations and you need to process them as r

HDU 3726 Graph and Queries treap树

题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct Node { Node *ch[2]; int r; int v; int s; Node(int v): v(v) { ch[0] = ch[1] = NULL; r = rand(); s

UVA 1479 - Graph and Queries(Treap)

UVA 1479 - Graph and Queries 题目链接 题意:给定一个n个结点m条边的无向图,每个结点一个权值,现在有3种操作 D x,删除id为x的边 Q x k 计算与x结点的连通分量中第k大的数字,不存在就是0 C x v 把x结点权值改为v 要求计算所有Q操作的和除以Q操作的次数的值 思路:Treap的经典题,进行离线操作,把操作全部逆向进行,删边就可以转化为加边,就可以利用并查集,那么维护第k大就利用Treap 代码: #include <cstdio> #include

hdu 3726 Graph and Queries(splay查询第k大,启发式合并,删除操作)

题目链接:hdu 3726 Graph and Queries 题意: 最开始给你n个点,每个点最开始有一个权值,并且都是独立的,现在给你m条边,表示对应的两个点是连接的. 现在有三种操作: Q x k,表示询问与x这个点联通的所有点中第k大的权值. D x,表示删除第x条边. C x y,表示改变x点的权值为y. 题解: 如果正着来做肯定比较麻烦,不好维护. 一看输出,可以离线处理,那么我们就倒着搞. 把所有的询问和边,点的变化全部存起来,然后用splay来维护. 每次删除就是倒着的合并,合并

uva 1479 - Graph and Queries(伸展树)

题目链接:uva 1479 - Graph and Queries 题目大意:有一张m条边的无向图,每个节点都有一个权值,现在有若干个操作, D x:删除ID为x的节点 Q x k:计算与节点x联通的节点当中,第k大的权值 C x v:把节点x的权值改为v 解题思路:把所有操作反过来处理,先执行所有的D操作,获得最终的图,然后逆操作的时候对于D来说即为合并操作,Q和C则是查询和修改操作. #include <cstdio> #include <cstring> #include &

UVALive 5031 Graph and Queries (Treap)

删除边的操作不容易实现一般就是先离线然后逆序来做. 逆序就变成了合并,用并存集判断连通,用Treap树来维护一个连通分量里的名次. Treap = Tree + Heap.就是用一个随机的优先级来平衡树. 名次查询需要维护树的结点数量,假设当前在u点,u的左子树有n个结点,那么u的就是以u为根的树上第n+1小的. 如果查询的不是n+1,那么根据结点数量判断一下在哪颗子树上,然后去查询. 树的合并就将结点数少的树上的点往结点数多的树里面插,然后删掉结点少的树. 修改权值就分解成删除点和插点. 写的

LA 5031 Graph and Queries —— Treap名次树

离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1logn2),由于合并之后原本结点数少的子树结点数至少翻倍,所以每个结点最多被插入 logn 次,故总时间复杂度为 O(n log2n)  . 注意细节处理,代码如下: 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstr

UVA 1479 Graph and Queries (Treap)

题意:给一个无向图,再给一系列操作(以下3种),输出最后的平均查询结果. (1)D X 删除第x条边. (2)Q X k  查询与点X相连的连通分量中第k大的点的权值. (3)C X v  将点X的权值改为v. 吐槽:第一次写的人儿,WA,MLE,TLE各种惨.而且还好我写过splay,不然坑得更惨.耗时整整一天半在查错. 思路: 第一点,由于需要删除边,不是很方便,所以可以先将所有操作存起来,反序来操作,这样删边就变成加边,方便了不少.每次加边时若两点不属于同个连通分量,就将点少的整个连通分量