zoukankan      html  css  js  c++  java
  • LA 5031 Graph and Queries —— Treap名次树

      离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度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
    ", ++kase, sum/double(cnt));
    176     }
    177     return 0;
    178 }
  • 相关阅读:
    c++常用库
    boost
    android
    UITableView 多选
    c++ 比较两个集合
    事件加不上的另一种原因
    ios多线程
    ubuntu android
    jna StdCallCallback 回调问题查证
    java
  • 原文地址:https://www.cnblogs.com/Kiraa/p/6184540.html
Copyright © 2011-2022 走看看