LA 5031 Graph and Queries —— Treap名次树

时间:2022-05-10 23:27:05

  离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度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 }