UVa 1479 (Treap 名次树) Graph and Queries
这题写起来真累。。
名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少。
所以在这道题中用一棵名次树来维护一个连通分量。
由于图中添边比较方便,用并查集来表示连通分量就好了,但是删边不太容易实现。
所以,先把所有的边删去,然后逆序执行命令。当然,C命令也要发生一些变化,比如说顺序的情况是从a变成b,那么逆序执行的话应该就是从b变成a。
最后两棵树的合并就是启发式合并,把节点数少的数并到节点数多的数里去。
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std; struct Node
{
Node* ch[];
int r, v, s;
Node(int v):v(v) { ch[] = ch[] = NULL; s = ; r = rand(); }
int cmp(int x)
{
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);
if(d == -)
{
if(o->ch[] == NULL) o = o->ch[];
else if(o->ch[] == NULL) o = o->ch[];
else
{
int d2 = o->ch[]->r < o->ch[]->r ? : ;
rotate(o, d2); remove(o->ch[d2], x);
}
}
else remove(o->ch[d], x);
if(o != NULL) o->maintain();
} const int maxc = + ;
struct Command
{
char type;
int x, p;
}cmd[maxc]; const int maxn = + ;
const int maxm = + ; int weight[maxn], from[maxm], to[maxm];
bool removed[maxm];
int n, m, query_cnt;
long long query_tot; int pa[maxn];
int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } Node* root[maxn]; int kth(Node* o, int k)
{
if(o == NULL || k <= || k > o->s) return ;
int s = o->ch[] == NULL ? : o->ch[]->s;
if(k == s + ) return o->v;
if(k <= s) return kth(o->ch[], k);
return kth(o->ch[], k - s - );
} void MergeTo(Node* &src, Node* &dest)
{
if(src->ch[] != NULL) MergeTo(src->ch[], dest);
if(src->ch[] != NULL) MergeTo(src->ch[], dest);
insert(dest, src->v);
delete src;
src = NULL;
} void RemoveTree(Node* &o)
{
if(o->ch[] != NULL) RemoveTree(o->ch[]);
if(o->ch[] != NULL) RemoveTree(o->ch[]);
delete o;
o = NULL;
} void AddEdge(int x)
{
int u = findset(from[x]);
int v = findset(to[x]);
if(u != v)
{
if(root[u]->s < root[v]->s) { pa[u] = v; MergeTo(root[u], root[v]); }
else { pa[v] = u; MergeTo(root[v], root[u]); }
}
} void Query(int x, int k)
{
query_cnt++;
query_tot += kth(root[findset(x)], k);
} void ChangeWeight(int x, int v)
{
int u = findset(x);
remove(root[u], weight[x]);
insert(root[u], v);
weight[x] = v;
} int main()
{
//freopen("in.txt", "r", stdin); 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++) scanf("%d%d", &from[i], &to[i]);
memset(removed, false, sizeof(removed)); int c = ;
for(;;)
{
char type[]; scanf("%s", type);
if(type[] == 'E') break;
int x, p = , v = ;
scanf("%d", &x);
if(type[] == 'D') removed[x] = true;
if(type[] == 'Q') scanf("%d", &p);
if(type[] == 'C')
{
scanf("%d", &v);
p = weight[x];
weight[x] = v;
}
cmd[c++] = (Command) { type[], x, p };
} for(int i = ; i <= n; i++)
{
pa[i] = i; if(root[i] != NULL) RemoveTree(root[i]);
root[i] = new Node(weight[i]);
}
for(int i = ; i <= m; i++) if(!removed[i]) AddEdge(i); query_cnt = query_tot = ;
for(int i = c - ; i >= ; i--)
{
char type = cmd[i].type;
int x = cmd[i].x, p = cmd[i].p;
if(type == 'D') AddEdge(x);
if(type == 'Q') Query(x, p);
if(type == 'C') ChangeWeight(x, p);
}
printf("Case %d: %.6f\n", ++kase, query_tot / (double)query_cnt);
} return ;
}
代码君
UVa 1479 (Treap 名次树) Graph and Queries的更多相关文章
- LA 5031 Graph and Queries —— Treap名次树
离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...
- 「模板」「讲解」Treap名次树
Treap实现名次树 前言 学平衡树的过程可以说是相当艰难.浏览Blog的过程中看到大量指针版平衡树,不擅长指针操作的我已经接近崩溃.于是,我想着一定要写一篇非指针实现的Treap的Blog. 具体如 ...
- POJ-1442 Black Box,treap名次树!
Black Box 唉,一天几乎就只做了这道题,成就感颇低啊! 题意:有一系列插入查找操作,插入每次 ...
- [la P5031&hdu P3726] Graph and Queries
[la P5031&hdu P3726] Graph and Queries Time Limit: 10000/5000 MS (Java/Others) Memory Limit: ...
- uvalive 5031 Graph and Queries 名次树+Treap
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...
- UVaLive5031 Graph and Queries(时光倒流+名次树)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332 [思路] 时光倒流+名次树(rank tree). 所谓“ ...
- HDU 3726 Graph and Queries treap树
题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring ...
- Treap和名次树
Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体.BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添 ...
- Treap 实现名次树
在主流STL版本中,set,map,都是BST实现的,具体来说是一种称为红黑树的动态平衡BST: 但是在竞赛中并不常用,因为红黑树过于复杂,他的插入 5 种,删除 6 中,代码量极大(如果你要改板子的 ...
随机推荐
- logback日志配置文件代码示例
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true&q ...
- A Product Array Puzzle
Given an array arr[] of n integers, construct a Product Array prod[] (of same size) such that prod[i ...
- ios 团购分类页面(9宫格)
=-= 命名有些错误,但功能实现,以后注意下命名规范 WJViewGroup.h #import <UIKit/UIKit.h> @interface WJViewGroup : UIVi ...
- POJ 1989
#include <iostream> #define MAXN 10005 using namespace std; bool mark[MAXN]; int main() { //fr ...
- 很不错的文章---【问底】徐汉彬:亿级Web系统搭建——单机到分布式集群
[导读]徐汉彬曾在阿里巴巴和腾讯从事4年多的技术研发工作,负责过日请求量过亿的Web系统升级与重构,目前在小满科技创业,从事SaaS服务技术建设. 大规模流量的网站架构,从来都是慢慢“成长”而来.而这 ...
- shape和selector的结合使用
shape和selector是Android UI设计中经常用到的,比如我们要自定义一个圆角Button,点击Button有些效果的变化,就要用到shape和selector.可以这样说,shape和 ...
- VS2012如何更新下载TFS上面的代码到本地
现在的代码基本上全都放在TFS上面,如何同步TFS上面的code呢? 1. Open "Team Explorer - Home" 2. Click "Source Co ...
- wamp中的phpmyadmin打开出现:#1045 - Access denied for user 'root'@'localhost' (using password: NO)
详细内容: MySQL said: #1045 - Access denied for user 'root'@'localhost' (using password: NO) phpMyAdmin ...
- C#:MapControl基本操作代码整理
整理了 MapConrol各基本功能的实现代码 using System; using System.Collections.Generic; using System.Linq; using Sys ...
- 【查找结构 2】二叉查找树 [BST]
当所有的静态查找结构添加和删除一个数据的时候,整个结构都需要重建.这对于常常需要在查找过程中动态改变数据而言,是灾难性的.因此人们就必须去寻找高效的动态查找结构,我们在这讨论一个非常常用的动态查找树— ...