LA 5031 Graph and Queries —— Treap名次树
离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1logn2),由于合并之后原本结点数少的子树结点数至少翻倍,所以每个结点最多被插入 logn 次,故总时间复杂度为
O(n log2n) 。
注意细节处理,代码如下:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; struct Node {
Node *ch[];
int r;
int v;
int s;
Node(int vv): v(vv) {
s = ;
ch[] = ch[] = NULL;
r = rand();
}
int cmp(int x) const {
if(x == v) return -;
return x < v ? : ;
}
void maintain() {
s = ;
if(ch[] != NULL) s += ch[]->s;
if(ch[] != NULL) s += ch[]->s;
}
}; void rotate(Node* &o, int d) {
Node* k = o->ch[d^]; o->ch[d^] = k->ch[d]; k->ch[d] = o;
o->maintain(); k->maintain(); o = k;
} void insert(Node* &o, int x) {
if(o == NULL) o = new Node(x);
else {
int d = x < o->v ? : ;
insert(o->ch[d], x);
if(o->ch[d]->r > o->r) rotate(o, d^);
}
o->maintain();
}
void remove(Node* &o, int x) {
int d = o->cmp(x);
Node* u = o;
if(d == -) {
if(o->ch[] != NULL && o->ch[] != NULL){
int d2 = o->ch[]->r > o->ch[]->r ? : ;
rotate(o, d2);
remove(o->ch[d2], x);
}
else {
if(o->ch[] == NULL) o = o->ch[]; else o = o->ch[];
delete u;
}
}
else remove(o->ch[d], x);
if(o != NULL) o->maintain();
} int kth(Node* o, int k) {
if(o == NULL || k > o->s || k <= ) return ;
int s = o->ch[] == NULL ? : o->ch[]->s;
if(k == s+) return o->v;
else if(k <= s) return kth(o->ch[], k);
else return kth(o->ch[], k-s-);
} struct cmd {
char type;
int x, p;
}; vector<cmd> cmds; const int maxn = 2e4 + ;
const int maxm = 6e4 + ;
int n, m;
int weight[maxn], from[maxm], to[maxm], removed[maxm]; int pa[maxn];
int findpa(int x) {return x == pa[x] ? x : pa[x] = findpa(pa[x]);}
long long sum;
int cnt;
Node* root[maxn]; void mergetreeto(Node* &ser, Node* &to) {
if(ser->ch[] != NULL) mergetreeto(ser->ch[], to);
if(ser->ch[] != NULL) mergetreeto(ser->ch[], to);
insert(to, ser->v);
delete ser;
ser = NULL;
} void removetree(Node *&ser) {
if(ser == NULL) return;
if(ser->ch[] != NULL) removetree(ser->ch[]);
if(ser->ch[] != NULL) removetree(ser->ch[]);
delete ser;
ser = NULL;
} void add_edge(int id) {
int x = findpa(pa[from[id]]);
int y = findpa(pa[to[id]]);
if(x != y) {
if(root[x]->s < root[y]->s) mergetreeto(root[x], root[y]), pa[x] = y;
else mergetreeto(root[y], root[x]), pa[y] = x;
}
} void querycnt(int x, int k) {
cnt++;
sum += kth(root[findpa(x)], k);
} void change_w(int x, int v) {
int u = findpa(pa[x]);
remove(root[u], weight[x]);
insert(root[u], v);
weight[x] = v;
} void init() {
cmds.clear();
cnt = ;
sum = ;
memset(removed, , sizeof removed);
for(int i = ; i < n; i++) removetree(root[i]);
}
int main() {
int kase = ;
while(scanf("%d%d", &n, &m) == && n) {
for(int i = ; i <= n; i++) scanf("%d", &weight[i]);
for(int i = ; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
from[i] = u;
to[i] = v;
}
init();
while() {
getchar();
char ch;
scanf("%c", &ch);
cmd C;
C.type = ch;
C.x = C.p = ;
if(ch == 'E') break;
scanf("%d", &C.x);
if(ch == 'D') removed[C.x] = ;
if(ch == 'Q') scanf("%d", &C.p);
if(ch == 'C') {
scanf("%d", &C.p);
swap(C.p, weight[C.x]);
}
cmds.push_back(C);
}
for(int i = ; i <= n; i++) {
pa[i] = i;
root[i] = new Node(weight[i]);
}
for(int i = ; i <= m; i++)
if(!removed[i]) add_edge(i); for(int i = cmds.size()-; i >= ; i--) {
cmd C = cmds[i];
if(C.type == 'D') add_edge(C.x);
if(C.type == 'C') change_w(C.x, C.p);
if(C.type == 'Q') querycnt(C.x, C.p);
}
printf("Case %d: %.6lf\n", ++kase, sum/double(cnt));
}
return ;
}
LA 5031 Graph and Queries —— Treap名次树的更多相关文章
- LA - 5031 - Graph and Queries
题意:一个N个点(编号从1开始),M条边的无向图(编号从1开始),有3种操作: D X:把编号为X的边删了: Q X K:查询编号为X的结点所在连通分量第K大的元素: C X V:将编号为X的结点的权 ...
- UVaLive 5031 Graph and Queries (Treap)
题意:初始时给出一个图,每个点有一个权值,三种操作:(1)删除某个边:(2)修改每个点的权值:(3)询问与节点x在一个连通分量中所有点的第K大的权值. 析:首先是要先离线,然后再倒着做,第一个操作就成 ...
- uvalive 5031 Graph and Queries 名次树+Treap
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...
- UVa 1479 (Treap 名次树) Graph and Queries
这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...
- HDU 3726 Graph and Queries treap树
题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring ...
- 「模板」「讲解」Treap名次树
Treap实现名次树 前言 学平衡树的过程可以说是相当艰难.浏览Blog的过程中看到大量指针版平衡树,不擅长指针操作的我已经接近崩溃.于是,我想着一定要写一篇非指针实现的Treap的Blog. 具体如 ...
- UVALive 5031 Graph and Queries (Treap)
删除边的操作不容易实现,那么就先离线然后逆序来做. 逆序就变成了合并,用并存集判断连通,用Treap树来维护一个连通分量里的名次. Treap = Tree + Heap.用一个随机的优先级来平衡搜索 ...
- UVALive - 5031 Graph and Queries (并查集+平衡树/线段树)
给定一个图,支持三种操作: 1.删除一条边 2.查询与x结点相连的第k大的结点 3.修改x结点的权值 解法:离线倒序操作,平衡树or线段树维护连通块中的所有结点信息,加个合并操作就行了. 感觉线段树要 ...
- UVALive5031 Graph and Queries(Treap)
反向操作,先求出最终状态,再反向操作. 然后就是Treap 的合并,求第K大值. #include<cstdio> #include<iostream> #include< ...
随机推荐
- redis数据库基本使用
redis数据库 # 1.安装redis与可视化操作工具 # 选择安装路径.圈中默认配置环境变量 # 2.在服务中管理redis服务器的开启关闭 # 3.命令行简单使用redis: -- redis- ...
- objectarx之判断给定的三点是否共线
bool ThreePointIsCollinear(const AcGePoint2d &pt1, const AcGePoint2d &pt2, const AcGePoint2d ...
- OSGi Capabilities
OSGi bundle的Capability就是这个bundle所具有的能力. 就像淘宝上的每个店铺一样,它会说明自己都卖哪些东西,也就是Provide-Capability 我们这些剁手党就会根据自 ...
- R是用于统计分析、绘图的语言和操作环境
R是一套完整的数据处理.计算和制图软件系统.其功能包括:数据存储和处理系统:数组运算工具(其向量.矩阵运算方面功能尤其强大):完整连贯的统计分析工具:优秀的统计制图功能:简便而强大的编程语言:可操纵数 ...
- 封装好的PDO类
封装PDO类,方便使用: <?php header('content-type:text/html;charset=utf-8'); /** * 封装PDODB类 */ // 加载接口 // i ...
- PHP进阶与redis锁限制并发访问功能示例
<?php /** * Redis锁操作类 * Date: 2017-06-30 * Author: fdipzone * Ver: 1.0 * * Func: * public lock 获取 ...
- Linux下配置 Keepalived(心跳检测部署)
首先呢,我想先给大家简单介绍一下什么是keepalived: Keepalived的作用是检测服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器 ...
- Python学习之路10☞面向对象进阶
一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 class Foo(objec ...
- Run As none applicable
详解如何在myeclipse中运行JSP,Run As none applicable(图) 内容提要:对JSP的访问都是用浏览器进行的,没有Run on Server这个选项. 在MyEclip ...
- java把Word文件转成html的字符串返回出去
1.需求是把前端上传的word文件解析出来,生成html的字符串返回给前端去展示,Word里面的图片可以忽略不显示,所以这段代码去掉了解析图片的代码 package com.lieni.core.ut ...