您的位置:首页 > 产品设计 > UI/UE

LA 5031 Graph and Queries —— Treap名次树

2016-12-15 19:44 423 查看

  离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1logn2),由于合并之后原本结点数少的子树结点数至少翻倍,所以每个结点最多被插入 logn 次,故总时间复杂度为  

O(n log2n)  。

注意细节处理,代码如下:

1 #include <cstdio>
2 #include <cstdlib>
3 #include <cstring>
4 #include <algorithm>
5 #include <vector>
6
7 using namespace std;
8
9
10 struct Node {
11     Node *ch[2];
12     int r;
13     int v;
14     int s;
15     Node(int vv): v(vv) {
16         s = 1;
17         ch[0] = ch[1] = NULL;
18         r = rand();
19     }
20     int cmp(int x) const {
21         if(x == v) return -1;
22         return x < v ? 0 : 1;
23     }
24     void maintain() {
25         s = 1;
26         if(ch[0] != NULL) s += ch[0]->s;
27         if(ch[1] != NULL) s += ch[1]->s;
28     }
29 };
30
31 void rotate(Node* &o, int d) {
32     Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
33     o->maintain(); k->maintain(); o = k;
34 }
35
36 void insert(Node* &o, int x) {
37     if(o == NULL) o = new Node(x);
38     else {
39         int d = x < o->v ? 0 : 1;
40         insert(o->ch[d], x);
41         if(o->ch[d]->r > o->r) rotate(o, d^1);
42     }
43     o->maintain();
44 }
45 void remove(Node* &o, int x) {
46     int d = o->cmp(x);
47     Node* u = o;
48     if(d == -1) {
49         if(o->ch[0] != NULL && o->ch[1] != NULL){
50             int d2 = o->ch[0]->r > o->ch[1]->r ? 1 : 0;
51             rotate(o, d2);
52             remove(o->ch[d2], x);
53         }
54         else {
55             if(o->ch[0] == NULL) o = o->ch[1]; else o = o->ch[0];
56             delete u;
57         }
58     }
59     else remove(o->ch[d], x);
60     if(o != NULL) o->maintain();
61 }
62
63 int kth(Node* o, int k) {
64     if(o == NULL || k > o->s || k <= 0) return 0;
65     int s = o->ch[1] == NULL ? 0 : o->ch[1]->s;
66     if(k == s+1) return o->v;
67     else if(k <= s) return kth(o->ch[1], k);
68     else return kth(o->ch[0], k-s-1);
69 }
70
71
72 struct cmd {
73     char type;
74     int x, p;
75 };
76
77 vector<cmd> cmds;
78
79 const int maxn = 2e4 + 10;
80 const int maxm = 6e4 + 10;
81 int n, m;
82 int weight[maxn], from[maxm], to[maxm], removed[maxm];
83
84 int pa[maxn];
85 int findpa(int x) {return x == pa[x] ? x : pa[x] = findpa(pa[x]);}
86 long long sum;
87 int cnt;
88 Node* root[maxn];
89
90 void mergetreeto(Node* &ser, Node* &to) {
91     if(ser->ch[0] != NULL) mergetreeto(ser->ch[0], to);
92     if(ser->ch[1] != NULL) mergetreeto(ser->ch[1], to);
93     insert(to, ser->v);
94     delete ser;
95     ser = NULL;
96 }
97
98 void removetree(Node *&ser) {
99     if(ser == NULL) return;
100     if(ser->ch[0] != NULL) removetree(ser->ch[0]);
101     if(ser->ch[1] != NULL) removetree(ser->ch[1]);
102     delete ser;
103     ser = NULL;
104 }
105
106 void add_edge(int id) {
107     int x = findpa(pa[from[id]]);
108     int y = findpa(pa[to[id]]);
109     if(x != y) {
110         if(root[x]->s < root[y]->s) mergetreeto(root[x], root[y]), pa[x] = y;
111         else mergetreeto(root[y], root[x]), pa[y] = x;
112     }
113 }
114
115 void querycnt(int x, int k) {
116     cnt++;
117     sum += kth(root[findpa(x)], k);
118 }
119
120 void change_w(int x, int v) {
121     int u = findpa(pa[x]);
122     remove(root[u], weight[x]);
123     insert(root[u], v);
124     weight[x] = v;
125 }
126
127 void init() {
128     cmds.clear();
129     cnt = 0;
130     sum = 0;
131     memset(removed, 0, sizeof removed);
132     for(int i = 1; i < n; i++) removetree(root[i]);
133 }
134 int main() {
135     int kase = 0;
136     while(scanf("%d%d", &n, &m) == 2 && n) {
137         for(int i = 1; i <= n; i++) scanf("%d", &weight[i]);
138         for(int i = 1; i <= m; i++) {
139             int u, v;
140             scanf("%d%d", &u, &v);
141             from[i] = u;
142             to[i] = v;
143         }
144         init();
145         while(1) {
146             getchar();
147             char ch;
148             scanf("%c", &ch);
149             cmd C;
150             C.type = ch;
151             C.x = C.p = 0;
152             if(ch == 'E') break;
153             scanf("%d", &C.x);
154             if(ch == 'D') removed[C.x] = 1;
155             if(ch == 'Q') scanf("%d", &C.p);
156             if(ch == 'C') {
157                 scanf("%d", &C.p);
158                 swap(C.p, weight[C.x]);
159             }
160             cmds.push_back(C);
161         }
162         for(int i = 1; i <= n; i++) {
163             pa[i] = i;
164             root[i] = new Node(weight[i]);
165         }
166         for(int i = 1; i <= m; i++)
167             if(!removed[i]) add_edge(i);
168
169         for(int i = cmds.size()-1; i >= 0; i--) {
170             cmd C = cmds[i];
171             if(C.type == 'D') add_edge(C.x);
172             if(C.type == 'C') change_w(C.x, C.p);
173             if(C.type == 'Q') querycnt(C.x, C.p);
174         }
175         printf("Case %d: %.6lf\n", ++kase, sum/double(cnt));
176     }
177     return 0;
178 }

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: