LA 5031 Graph and Queries (Treap + 并查集)

题目连接

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3032

完全照着大白抄的,没什么好说的。。

不过一个地方打错了,RE了好久%>_<%

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<cstdlib>
using namespace std;

#define inf 0x3f3f3f3f
#define eps 1e-8
#define LL long long 
#define ULL unsigned long long
#define MP make_pair

const int mxc = 1000000 + 10;
const int mxn = 200000 + 10;
const int mxm = 600000 + 10;

struct node {
	node *ch[10];
	int r, v, s;
	node( int v ): v( v ) {
		ch[0] = ch[1] = NULL;
		r = rand();
		s = 1;
	}
	bool operator < ( const node &b ) const {
		return r < b.r;
	}
	int cmp( int x ) const {
		if( v == x )
			return -1;
		return x < v ? 0 : 1;
	}
	void mt() {
		s = 1;
		if( ch[0] )
			s += ch[0] -> s;
		if( ch[1] )
			s += ch[1] -> s;
	}
};
void rt( node *&o, int d ) {
	node *k = o -> ch[d^1];
	o -> ch[d^1] = k -> ch[d];
	k -> ch[d] = o;
	o -> mt();
	k -> mt();
	o = k;
}
void insert( node *&o, int x ) {
	if( o == NULL )
		o = new node( x );
	else {
		int d = x < o -> v ? 0 : 1;
		insert( o -> ch[d], x );
		if( o -> ch[d] -> r > o -> r ) {
			rt( o, d ^ 1 );
		}
	}
	o -> mt();
}
void remove( node *&o, int x ) {
	int d = o -> cmp( x );
	if( d == -1 ) {
		node *u = o;
		if( o -> ch[0] && o -> ch[1] ) {
			int d2 = ( o -> ch[0] -> r > o -> ch[1] -> r ? 1 : 0 );
			rt( o, d2 );
			remove( o -> ch[d2], x );
		}
		else {
			if( o -> ch[0] == NULL )
				o = o -> ch[1];
			else
				o = o -> ch[0];
			delete u;
		}
	}
	else
		remove( o -> ch[d], x );
	if( o )
		o -> mt();
}

struct Com {
	char type;
	int x, p;
	Com(){}
	Com( char type, int x, int p ): type( type ), x( x ), p( p ) {}
}com[mxc];

int n, m, w[mxn], from[mxm], to[mxm], vis[mxm];
int fa[mxn];
int findset( int x ) {
	if( fa[x] != x )
		fa[x] = findset( fa[x] );
	return fa[x];
}
node *root[mxn];

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( k == s + 1 )
		return o -> v;
	if( k <= s )
		return kth( o -> ch[1], k );
	return kth( o -> ch[0], k - s - 1 );
}
void merge( node *&i, node *&j ) {
	if( i -> ch[0] )
		merge( i -> ch[0], j );
	if( i -> ch[1] )
		merge( i -> ch[1], j );
	insert( j, i -> v );
	delete i;
	i = NULL;
}
void removetree( node *& x ) {
	if( x -> ch[0] )
		removetree( x -> ch[0] );
	if( x -> ch[1] )
		removetree( x -> ch[1] );
	delete x;
	x = NULL;
}
void add_edge( int x ) {
	int u = findset( from[x] ), v = findset( to[x] );
	if( u != v ) {
		if( root[u] -> s < root[v] -> s ) {
			fa[u] = v;
			merge( root[u], root[v] );
		}
		else {
			fa[v] = u;
			merge( root[v], root[u] );
		}
	}
}
int qc;
LL qt;
void query( int x, int k ) {
	qc ++;
	qt += kth( root[findset(x)], k );
}
void update( int x, int v ) {
	int u = findset( x );
	remove( root[u], w[x] );
	insert( root[u], v );
	w[x] = v;
}
int main() {
	int cas = 0;
	while( scanf( "%d%d", &n, &m ) == 2 && n ) {
		for( int i = 1; i <= n; ++i ) 
			scanf( "%d", &w[i] );
		for( int i = 1; i <= m; ++i ) 
			scanf( "%d%d", &from[i], &to[i] );
		memset( vis, 0, sizeof( vis ) );
		int c = 0;
		while( 1 ) {
			char type;
			int x, p = 0, v = 0;
			scanf( " %c", &type );
			if( type == 'E' )
				break;
			scanf( "%d", &x );
			if( type == 'D' )
				vis[x] = 1;
			if( type == 'Q' )
				scanf( "%d", &p );
			if( type == 'C' ) {
				scanf( "%d", &v );
				p = w[x];
				w[x] = v;
			}
			Com tem( type, x, p );
			com[c++] = tem;
		}
		for( int i = 1; i <= n; ++i ) {
			fa[i] = i;
			if( root[i] )
				removetree( root[i] );
			root[i] = new node( w[i] );
		}
		for( int i = 1; i <= m; ++i )
			if( !vis[i] )
				add_edge( i );
		qt = qc = 0;
		for( int i = c - 1; i >= 0; -- i ) {
			if( com[i].type == 'D' )
				add_edge( com[i].x );
			if( com[i].type == 'Q' )
				query( com[i].x, com[i].p );
			if( com[i].type == 'C' )
				update( com[i].x, com[i].p );
		}
		printf( "Case %d: %.6lf\n", ++cas, qt / ( double ) qc );
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值