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;    
}

 

  

posted @ 2013-04-09 20:29  yefeng1627  阅读(671)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor