• hdu 3726 Graph and Queries 10天津赛区 离线算法+treap维护名次树


    题意

      n(n<=2e4)个顶点m(m<=6e4)条边,每个顶点有个权值val_i, 然后有Q(Q<=5e5)次操作.

      操作分为三类:

        D x : 删除第x条边

        Q x k : 查询与节点x关联的所有顶点中第k大

        C x V : 将节点x的权值更改为V

      输出查询的均值  /sum { Query_val } / Query_num

    解题思路

      离线算法

      对于删除,可以通过将所有操作读入后,从后往前处理。把删除边转换成插入边。

      对于查询第k大顶点,我们可以使用 treap维护的名次树 kth来实现

      对于修改操作,我们先将原来的值删除,然后再插入新值。 因为我们使用离线逆向处理,则修改操作也会逆向。

      

      关于名次树,只是对于 treap上增加了一个 size(其子节点的数量和+1)然后来实现求第K大 or 小.

      核心代码:

    int kth(Node *o, int k){
        if( o==NULL || k <= 0 || k > o->s ) return 0;
        int s = o->ch[1] == NULL ? 0 : o->ch[1]->s;
        if( s+1 == k )    return o->k;
        if( s >= k ) return kth( o->ch[1], k );
        else    return kth( o->ch[0], k-(s+1) );
    }

    解题代码:

      

    View Code
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    typedef long long LL;
    const int N = 2e4+10;
    const int M = 6e4+10;
    
    // 名次树 
    struct Node{
        Node *ch[2];
        int k, r, s;
        Node(int x):k(x){ch[0]=ch[1]=NULL;r=rand();s=1;}    
        int cmp(int x){
            if( k == x ) return -1;
            return x < k ? 0 : 1;
        }
        void maintain(){
            s = 1;
            if( ch[0] != NULL ) s += ch[0]->s;
            if( ch[1] != NULL ) s += ch[1]->s;    
        }
    };
    void rotate(Node* &o, int d){
        Node *t = o->ch[d^1];
        o->ch[d^1] = t->ch[d];
        t->ch[d] = o;
        o->maintain(); t->maintain(); 
        o = t;
    }
    void insert(Node* &o, int x){
        if( o == NULL ) o = new Node(x);    
        else{
            int d = x < o->k ? 0 : 1;
            insert( o->ch[d], x );    
            if( o->ch[d]->r > o->r ) rotate( o, d^1 );
        }
        o->maintain();
    }
    void remove(Node* &o, int x){
        int d = o->cmp(x);
        if( d == -1 ){
            if( o->ch[0]!=NULL && o->ch[1]!=NULL ){
                int d2 = o->ch[0]->r > o->ch[1]->r ? 1 : 0;
                rotate( o, d2 ); remove( o->ch[d2], x );    
            }
            else{
                Node *t = o; 
                if( o->ch[0] == NULL ) o = o->ch[1];
                else o = o->ch[0];    
                delete t; // take into attentions to delete the space of point
            }
        }
        else    remove( o->ch[d], x );
        if( o != NULL ) o->maintain();
    }
    int kth(Node *o, int k){
        if( o==NULL || k <= 0 || k > o->s ) return 0;
        int s = o->ch[1] == NULL ? 0 : o->ch[1]->s;
        if( s+1 == k )    return o->k;
        if( s >= k ) return kth( o->ch[1], k );
        else    return kth( o->ch[0], k-(s+1) );
    }
    
    struct Command{
        char type;
        int x, y;    
    }commands[500010];
    int n, m, cnt;
    int val[N], st[N], from[M], to[M];
    bool removed[M];
    LL query_sum;
    int query_num;
    Node *root[N];
    
    int find( int x ){ return x==st[x]?x:(st[x]=find(st[x]));}
    void mergeto( Node* &src, Node* &dest ){
        if( src->ch[0] != NULL ) mergeto( src->ch[0], dest );
        if( src->ch[1] != NULL ) mergeto( src->ch[1], dest );
        insert( dest, src->k );
        delete src; src = NULL;    
    }
    void addedge( int x ){
        int a = find(from[x]), b = find(to[x]);
        if( a != b ){
            if( root[a]->s < root[b]->s ){
                st[a] = b; mergeto( root[a], root[b] );    
            }    
            else{
                st[b] = a; mergeto( root[b], root[a] );    
            }
        }    
    }
    
    void remove_tree( Node* &o ){
        if( o->ch[0] != NULL ) remove_tree( o->ch[0] );
        if( o->ch[1] != NULL ) remove_tree( o->ch[1] );
        delete o; o = NULL;    
    }
    void Query( int x, int k ){ 
        query_sum += kth( root[ find(x) ], k );  
        query_num++;
    }
    void Update( int x, int k ){
        int a = find(x);
        remove( root[a], val[x] );
        insert( root[a], k );
        val[x] = k;    
    }
    
    void pre_deal(){
        char op[2];
        int x, y;
        // Edge ralationship
        for(int i = 1; i <= n; i++)
            scanf("%d", &val[i] );
        for(int i = 1; i <= m; i++)
            scanf("%d%d", &from[i],&to[i] );
        // Command request
        cnt = 0; 
        memset( removed, 0, sizeof(removed) );
        while( scanf("%s", op) != EOF ){
            if( op[0] == 'E' ) break;
            scanf("%d", &x);
            if( op[0] == 'D' ) removed[x] = 1;
            if( op[0] == 'Q' ) scanf("%d", &y);
            if( op[0] == 'C' ){
                scanf("%d", &y);
                int t = y;
                y = val[x];
                val[x] = t;    
            }
            commands[cnt].type = op[0];
            commands[cnt].x = x;
            commands[cnt++].y = y;
        } 
        // init point
        for(int i = 1; i <= n; i++){
            st[i] = i;
            if( root[i] != NULL ) remove_tree( root[i] );
            root[i] = new Node(val[i]);    
        } 
        // init the edge
        for(int i = 1; i <= m; i++)
            if( !removed[i] ) addedge( i );
    }
    void solve( int Case ){
        query_sum = 0; query_num = 0;
        for(int i = cnt-1; i >= 0; i-- ){
            if( commands[i].type == 'D' ) addedge( commands[i].x );
            if( commands[i].type == 'Q' ) Query( commands[i].x, commands[i].y );
            if( commands[i].type == 'C' ) Update( commands[i].x, commands[i].y );    
        }     
    //    printf("sum = %lld\n", query_sum );
    //    printf("num = %d\n", query_num );
        printf("Case %d: %.6lf\n", Case, 1.*query_sum/query_num );
    }
    int main(){ 
        int Case = 1; 
        while( scanf("%d%d",&n,&m), n+m ){
            pre_deal();
            solve( Case++ );    
        }
        return 0;    
    }

      

  • 相关阅读:
    【题解】 P1373 小a和uim之大逃离
    题解 CF576C 【Points on Plane】
    题解 P4799 【[CEOI2015 Day2]世界冰球锦标赛】
    【题解】[JSOI2008]最大数
    题解 P3389 【【模板】高斯消元法】
    【模板】矩阵加速
    【模板】树状数组上的差分数组
    tarjan求强连通分量(模板)
    我好菜系列——map查找
    trie树的应用;
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3010935.html
Copyright © 2020-2023  润新知