• 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         ch[0] = ch[1] = NULL;
     12         r = rand();
     13         s = 1;
     14     }
     15     int cmp(int x) const
     16     {
     17         if (x == v) return -1;
     18         return x < v ? 0 : 1;
     19     }
     20     void maintain()
     21     {
     22         s = 1;
     23         if(ch[0] != NULL) s += ch[0]->s;
     24         if(ch[1] != NULL) s += ch[1]->s;
     25     }
     26 };
     27 
     28 void rotate(Node* &o, int d)
     29 {
     30     Node* k = o->ch[d^1];
     31     o->ch[d^1] = k->ch[d];
     32     k->ch[d] = o;
     33     o->maintain();
     34     k->maintain();
     35     o = k;
     36 }
     37 
     38 void insert(Node* &o, int x)
     39 {
     40     if(o == NULL) o = new Node(x);
     41     else
     42     {
     43         int d = (x < o->v ? 0 : 1); // 不要用cmp函数,因为可能会有相同结点
     44         insert(o->ch[d], x);
     45         if(o->ch[d]->r > o->r) rotate(o, d^1);
     46     }
     47     o->maintain();
     48 }
     49 
     50 void remove(Node* &o, int x)
     51 {
     52     int d = o->cmp(x);
     53     int ret = 0;
     54     if(d == -1)
     55     {
     56         Node* u = o;
     57         if(o->ch[0] != NULL && o->ch[1] != NULL)
     58         {
     59             int d2 = (o->ch[0]->r > o->ch[1]->r ? 1 : 0);
     60             rotate(o, d2);
     61             remove(o->ch[d2], x);
     62         }
     63         else
     64         {
     65             if(o->ch[0] == NULL) o = o->ch[1];
     66             else o = o->ch[0];
     67             delete u;
     68         }
     69     }
     70     else
     71         remove(o->ch[d], x);
     72     if(o != NULL) o->maintain();
     73 }
     74 
     75 #include<cstdio>
     76 #include<cstring>
     77 #include<vector>
     78 using namespace std;
     79 
     80 const int maxc = 500000 + 10;
     81 struct Command
     82 {
     83     char type;
     84     int x, p; // 根据type, p代表k或者v
     85 } commands[maxc];
     86 
     87 const int maxn = 20000 + 10;
     88 const int maxm = 60000 + 10;
     89 int n, m, weight[maxn], from[maxm], to[maxm], removed[maxm];
     90 
     91 // 并查集相关
     92 int pa[maxn];
     93 int findset(int x)
     94 {
     95     return pa[x] != x ? pa[x] = findset(pa[x]) : x;
     96 }
     97 
     98 // 名次树相关
     99 Node* root[maxn]; // Treap
    100 
    101 int kth(Node* o, int k)   // 第k大的值
    102 {
    103     if(o == NULL || k <= 0 || k > o->s) return 0;
    104     int s = (o->ch[1] == NULL ? 0 : o->ch[1]->s);
    105     if(k == s+1) return o->v;
    106     else if(k <= s) return kth(o->ch[1], k);
    107     else return kth(o->ch[0], k-s-1);
    108 }
    109 
    110 void mergeto(Node* &src, Node* &dest)
    111 {
    112     if(src->ch[0] != NULL) mergeto(src->ch[0], dest);
    113     if(src->ch[1] != NULL) mergeto(src->ch[1], dest);
    114     insert(dest, src->v);
    115     delete src;
    116     src = NULL;
    117 }
    118 
    119 void removetree(Node* &x)
    120 {
    121     if(x->ch[0] != NULL) removetree(x->ch[0]);
    122     if(x->ch[1] != NULL) removetree(x->ch[1]);
    123     delete x;
    124     x = NULL;
    125 }
    126 
    127 // 主程序相关
    128 void add_edge(int x)
    129 {
    130     int u = findset(from[x]), v = findset(to[x]);
    131     if(u != v)
    132     {
    133         if(root[u]->s < root[v]->s)
    134         {
    135             pa[u] = v;
    136             mergeto(root[u], root[v]);
    137         }
    138         else
    139         {
    140             pa[v] = u;
    141             mergeto(root[v], root[u]);
    142         }
    143     }
    144 }
    145 
    146 int query_cnt;
    147 long long query_tot;
    148 void query(int x, int k)
    149 {
    150     query_cnt++;
    151     query_tot += kth(root[findset(x)], k);
    152 }
    153 
    154 void change_weight(int x, int v)
    155 {
    156     int u = findset(x);
    157     remove(root[u], weight[x]);
    158     insert(root[u], v);
    159     weight[x] = v;
    160 }
    161 
    162 int main()
    163 {
    164     int kase = 0;
    165     while(scanf("%d%d", &n, &m) == 2 && n)
    166     {
    167         for(int i = 1; i <= n; i++) scanf("%d", &weight[i]);
    168         for(int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]);
    169         memset(removed, 0, sizeof(removed));
    170 
    171         // 读命令
    172         int c = 0;
    173         for(;;)
    174         {
    175             char type;
    176             int x, p = 0, v = 0;
    177             scanf(" %c", &type);
    178             if(type == 'E') break;
    179             scanf("%d", &x);
    180             if(type == 'D') removed[x] = 1;
    181             if(type == 'Q') scanf("%d", &p);
    182             if(type == 'C')
    183             {
    184                 scanf("%d", &v);
    185                 p = weight[x];
    186                 weight[x] = v;
    187             }
    188             commands[c++] = (Command)
    189             {
    190                 type, x, p
    191             };
    192         }
    193 
    194         // 最终的图
    195         for(int i = 1; i <= n; i++)
    196         {
    197             pa[i] = i;
    198             if(root[i] != NULL) removetree(root[i]);
    199             root[i] = new Node(weight[i]);
    200         }
    201         for(int i = 1; i <= m; i++) if(!removed[i]) add_edge(i);
    202 
    203         // 反向操作
    204         query_tot = query_cnt = 0;
    205         for(int i = c-1; i >= 0; i--)
    206         {
    207             if(commands[i].type == 'D') add_edge(commands[i].x);
    208             if(commands[i].type == 'Q') query(commands[i].x, commands[i].p);
    209             if(commands[i].type == 'C') change_weight(commands[i].x, commands[i].p);
    210         }
    211         printf("Case %d: %.6lf
    ", ++kase, query_tot / (double)query_cnt);
    212     }
    213     return 0;
    214 }
    View Code
  • 相关阅读:
    Linux下如何确认磁盘是否为SSD
    Nginx
    求两个Linux文本文件的交集、差集、并集
    DB磁盘满导致Zabbix Server Crash一例
    配置SSH Forward提升安全性
    更新ffmpeg
    linux系统日志__ratelimit: N callbacks suppressed
    servlet本质
    session与cookie的区别与联系
    Leetcode 19——Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/ITUPC/p/5074251.html
Copyright © 2020-2023  润新知