zoukankan      html  css  js  c++  java
  • LA 5031 图询问

    题目链接:https://vjudge.net/contest/159527#problem/A

    题意:(求一个 图 中的连通分量中的 第 k 大)

    一张图,n 个点,m 条边,

    有一些操作:

    删除 ID 为 x 的边,(从 1 到 m);

    询问 x 所在的连通分量 里面第 k 大的权值;

    把结点 X 的权值 改成 V;

    求:

    所有的询问后,计算平均值;

    每个连通分量都是一颗Treap树,加边操作,就是树的合并;

    刘汝佳采用的是离线算法,我还是第一次听说,但是还是可以按照题意直接模拟的(我猜,但是很麻烦);因为在Treap中删边不同于删点;

    什么是离线算法呢?

    把操作顺序反过来处理,执行完所有 删除边操作,然后建Treap,要是不在同一个连通分量里面(并查集判断),这就涉及到递归合并Treap树了,这里采用了启发式合并;

    然后反向操作,遇到 D,就是加边(加边操作同上),

    询问,就是在 X 所在连通分量里面,寻找第 k 大;

    改权,就是删除这个点,然后从新加点;

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 struct Node
      6 {
      7     Node *ch[2];
      8     int r;  //优先级
      9     int v;  //
     10     int s;  //结点总数
     11 
     12     Node(int v):v(v)
     13     {
     14         ch[0] = ch[1] = NULL;
     15         r = rand();
     16         s = 1;
     17     }
     18 
     19     bool operator < (const Node& rhs) const
     20     {
     21         return r < rhs.r;
     22     }
     23 
     24     int cmp(int x) const
     25     {
     26         if(x==v) return -1;
     27         return x < v ? 0 : 1;
     28     }
     29 
     30     void maintain()
     31     {
     32         s = 1;
     33         if(ch[0]!=NULL) s+=ch[0]->s;
     34         if(ch[1]!=NULL) s+=ch[1]->s;
     35     }
     36 
     37 
     38 };
     39 
     40 void rotate(Node* &o,int d)
     41 {
     42     Node* k = o->ch[d^1];
     43     o->ch[d^1] = k ->ch[d];
     44     k->ch[d] = o;
     45     o->maintain();
     46     k->maintain();
     47     o = k;
     48 }
     49 
     50 void insert(Node* &o,int x)
     51 {
     52     if(o==NULL) o = new Node(x);
     53     else
     54     {
     55         int d = (x < o->v? 0 : 1);
     56         insert(o->ch[d],x);
     57         if(o->ch[d]->r > o->r)
     58             rotate(o,d^1);
     59     }
     60     o->maintain();
     61 }
     62 
     63 void remove(Node* &o,int x)
     64 {
     65     int d = o->cmp(x);
     66     if(d==-1)
     67     {
     68         Node* u = 0;
     69         if(o->ch[0]!=NULL&&o->ch[1]!=NULL)
     70         {
     71             int d2 = (o->ch[0]->r > o->ch[1]->r ? 1 : 0);
     72             rotate(o,d2);
     73             remove(o->ch[d2],x);
     74         }
     75         else
     76         {
     77             if(o->ch[0]==NULL)
     78                 o = o->ch[1];
     79             else o = o->ch[0];
     80         }
     81     }
     82     else
     83         remove(o->ch[d],x);
     84 
     85     if(o!=NULL) o->maintain();
     86 }
     87 
     88 
     89 const int maxc = 500000 + 10;
     90 struct Command
     91 {
     92     char type;
     93     int x,p;
     94 } commands[maxc];
     95 
     96 const int maxn = 20000 + 10;
     97 const int maxm = 60000 + 10;
     98 int n,m;
     99 int weight[maxn],from[maxm],to[maxm],removed[maxm];
    100 
    101 
    102 int pa[maxn];
    103 int findset(int x)
    104 {
    105     return pa[x]!=x ? pa[x] = findset(pa[x]):x;
    106 }
    107 
    108 Node* root[maxn];   //Treap
    109 
    110 int kth(Node* o,int k)
    111 {
    112     if(o==NULL||k<=0||k> o->s) return 0;
    113     int s = (o->ch[1]==NULL?0:o->ch[1]->s);
    114     if(k==s+1) return o->v;
    115     else if(k<=s) return kth(o->ch[1],k);
    116     else return kth(o->ch[0],k-s-1);
    117 }
    118 
    119 void mergeto(Node* &src,Node* &dest)
    120 {
    121     if(src->ch[0]!=NULL) mergeto(src->ch[0],dest);
    122     if(src->ch[1]!=NULL) mergeto(src->ch[1],dest);
    123     insert(dest,src->v);
    124     delete src;
    125     src = NULL;
    126 }
    127 
    128 void removetree(Node* &x)
    129 {
    130     if(x->ch[0]!=NULL) removetree(x->ch[0]);
    131     if(x->ch[1]!=NULL) removetree(x->ch[1]);
    132     delete x;
    133     x = NULL;
    134 }
    135 
    136 void add_edge(int x)
    137 {
    138     int u = findset(from[x]),v=findset(to[x]);
    139     if(u!=v)
    140     {
    141         if(root[u]->s < root[v]->s)
    142         {
    143             pa[u] = v;
    144             mergeto(root[u],root[v]);
    145         }
    146         else
    147         {
    148             pa[v] = u;
    149             mergeto(root[v],root[u]);
    150         }
    151     }
    152 }
    153 
    154 int query_cnt;
    155 long long query_tot;
    156 void query(int x,int k)
    157 {
    158     query_cnt++;
    159     query_tot +=kth(root[findset(x)],k);
    160 }
    161 
    162 void change_weight(int x,int v)
    163 {
    164     int u = findset(x);
    165     remove(root[u],weight[x]);
    166     insert(root[u],v);
    167     weight[x] = v;
    168 }
    169 
    170 
    171 int main()
    172 {
    173     int kase = 0;
    174     while(scanf("%d%d",&n,&m)==2&&n)
    175     {
    176         for(int i=1; i<=n; i++)
    177             scanf("%d",&weight[i]);
    178         for(int i=1; i<=m; i++)
    179             scanf("%d%d",&from[i],&to[i]);
    180         memset(removed,0,sizeof(removed));
    181 
    182         int c = 0;
    183         for(;;)
    184         {
    185             char type;
    186             int x,p=0,v = 0;
    187             scanf(" %c",&type);
    188             if(type=='E') break;
    189             scanf("%d",&x);
    190             if(type=='D') removed[x]= 1;    //删掉的边
    191             if(type=='Q') scanf("%d",&p);
    192             if(type=='C')
    193             {
    194                 scanf("%d",&v);
    195                 p = weight[x];
    196                 weight[x] = v;
    197             }
    198             commands[c++] = (Command)
    199             {
    200                 type,x,p
    201             };
    202         }
    203 
    204         //最终的图
    205         for(int i=1; i<=n; i++)
    206         {
    207             pa[i] = i;
    208             if(root[i]!=NULL) removetree(root[i]);
    209             root[i] = new Node(weight[i]);
    210         }
    211         for(int i=1; i<=m; i++)
    212         {
    213             if(!removed[i]) //id为i这条边没有被删掉
    214                 add_edge(i);
    215         }
    216 
    217         query_cnt = query_tot = 0;
    218         for(int i=c-1; i>=0; i--)
    219         {
    220             if(commands[i].type=='D') add_edge(commands[i].x);  //加上边
    221             if(commands[i].type=='Q') query(commands[i].x,commands[i].p);//第p大
    222             if(commands[i].type=='C') change_weight(commands[i].x,commands[i].p);
    223         }
    224 
    225         printf("Case %d: %.6lf
    ",++kase,query_tot/(double)query_cnt);
    226 
    227     }
    228 
    229 
    230 
    231     return 0;
    232 }
    View Code
  • 相关阅读:
    Codeforces 845E Fire in the City 线段树
    Codeforces 542D Superhero's Job dp (看题解)
    Codeforces 797F Mice and Holes dp
    Codeforces 408D Parcels dp (看题解)
    Codeforces 464D World of Darkraft
    Codeforces 215E Periodical Numbers 容斥原理
    Codeforces 285E Positions in Permutations dp + 容斥原理
    Codeforces 875E Delivery Club dp
    Codeforces 888F Connecting Vertices 区间dp (看题解)
    Codeforces 946F Fibonacci String Subsequences dp (看题解)
  • 原文地址:https://www.cnblogs.com/TreeDream/p/6735840.html
Copyright © 2011-2022 走看看