反向操作,先求出最终状态,再反向操作。

然后就是Treap 的合并,求第K大值。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<cmath>
#include<utility>
using namespace std;
typedef long long LL;
struct Treap{
int size,key,pri;
Treap *ch[2];
Treap(int key){
size=1;
pri=rand();
this->key=key;
ch[0]=ch[1]=NULL;
}
int compare(int x) const{
if(x==key) return -1;
return x<key? 0:1;
}
void Maintain(){
size=1;
if(ch[0]!=NULL){
size+=ch[0]->size;
}
if(ch[1]!=NULL){
size+=ch[1]->size;
}
}
}; void Rotate(Treap* &t,int d){
Treap *k=t->ch[d^1];
t->ch[d^1]=k->ch[d];
k->ch[d]=t;
t->Maintain();
k->Maintain();
t=k;
} void Insert(Treap* &t,int x){
if(t==NULL){
t=new Treap(x);
}else{
int d=x < t->key ? 0:1;
Insert(t->ch[d],x);
if(t->ch[d]->pri > t->pri){
Rotate(t,d^1);
}
}
t->Maintain();
} void Delete(Treap* &t,int x){
int d=t->compare(x);
if(d==-1){
Treap *tmp=t;
if(t->ch[0]==NULL){
t=t->ch[1];
delete tmp;
tmp=NULL;
}else if(t->ch[1]==NULL){
t=t->ch[0];
delete tmp;
tmp=NULL;
}else{
int k=t->ch[0]->pri > t->ch[1]->pri ? 1:0;
Rotate(t,k);
Delete(t->ch[k],x);
}
}else{
Delete(t->ch[d],x);
}
if(t!=NULL){
t->Maintain();
}
} int Kth(Treap *t,int k){
if(t==NULL||k<=0||k>t->size){
return 0;
}
if(t->ch[0]==NULL&&k==1){
return t->key;
}
if(t->ch[0]==NULL){
return Kth(t->ch[1],k-1);
}
if(t->ch[0]->size>=k){
return Kth(t->ch[0],k);
}
if(t->ch[0]->size+1==k){
return t->key;
}
return Kth(t->ch[1],k-1-t->ch[0]->size);
} void DeleteTreap(Treap* &t){//删除,释放内存
if(t==NULL) return;
if(t->ch[0]!=NULL){
DeleteTreap(t->ch[0]);
}
if(t->ch[1]!=NULL){
DeleteTreap(t->ch[1]);
}
delete t;
t=NULL;
} int n, m;
int g[100000][3];
stack<int> val[40000];
struct Ope{
char t;
int a, b;
void init(char t1, int a1 = 0, int b1 = 0){
t = t1;
a = a1;
b = b1;
}
}op[1000000]; int fa[40000];
Treap* fax[40000]; void mergeTreap(Treap* &a, Treap* &b){
if(a){
if(a -> ch[0]){
mergeTreap(a -> ch[0], b);
}
if(a -> ch[1]){
mergeTreap(a -> ch[1], b);
}
Insert(b, a -> key);
delete a;
a = NULL;
}
} int uFind(int x){
return (fa[x] == x) ? x : fa[x] = uFind(fa[x]);
} void add(int u, int v){
int fx = uFind(u);
int fy = uFind(v);
if(fx != fy){
if(fax[fx] -> size < fax[fy] -> size){
mergeTreap(fax[fx], fax[fy]);
fa[fx] = fy;
}else{
mergeTreap(fax[fy], fax[fx]);
fa[fy] = fx;
} }
} int main(){
int cas = 0;
while(~scanf("%d %d", &n, &m) && n || m){
for(int i = 1; i <= n; i++){
fa[i] = i;
fax[i] = NULL;
int tp;
scanf("%d", &tp);
tp = -tp;
while(!val[i].empty()){
val[i].pop();
}
val[i].push(tp);
}
for(int i = 0; i < m; i++){
int u, v;
scanf("%d %d", &u, &v);
g[i][0] = u;
g[i][1] = v;
g[i][2] = 0;
}
char str[10];
int tot = 0;
while(~scanf("%s", str) && str[0] != 'E'){
int a, b;
if(str[0] == 'D'){
scanf("%d", &a);
a--;
g[a][2] = 1;
}else if(str[0] == 'C'){
scanf("%d %d", &a, &b);
b = -b;
val[a].push(b);
}else{
scanf("%d %d", &a, &b);
}
op[tot++].init(str[0], a, b); }
for(int i = 1; i <= n; i++){
Insert(fax[i], val[i].top());
}
for(int i = 0; i < m; i++){
if(g[i][2] == 0){
add(g[i][0], g[i][1]);
}
}
int cnt = 0;
LL ans = 0;
while(tot--){
if(op[tot].t == 'C'){
int rt = uFind(op[tot].a);
Delete(fax[rt], val[op[tot].a].top());
val[op[tot].a].pop(); Insert(fax[rt], val[op[tot].a].top()); }else if(op[tot].t == 'D'){
int id = op[tot].a;
add(g[id][0], g[id][1]);
}else{
cnt++;
ans += Kth(fax[ uFind(op[tot].a) ], op[tot].b);
}
}
printf("Case %d: %.6f\n", ++cas, (double)-ans / cnt);
for(int i = 1; i <= n; i++){
int fx = uFind(i);
if(fax[fx] != NULL){
DeleteTreap(fax[fx]);
}
}
} return 0;
}

已经释放了内存,但在VS中使用_CrtDumpMemoryLeaks()函数检查还是有内存泄漏问题,原因还没弄清楚

UVALive5031 Graph and Queries(Treap)的更多相关文章

  1. HDU 3726 Graph and Queries treap树

    题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring ...

  2. UVaLive5031 Graph and Queries(时光倒流+名次树)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332 [思路] 时光倒流+名次树(rank tree). 所谓“ ...

  3. UVaLive 5031 Graph and Queries (Treap)

    题意:初始时给出一个图,每个点有一个权值,三种操作:(1)删除某个边:(2)修改每个点的权值:(3)询问与节点x在一个连通分量中所有点的第K大的权值. 析:首先是要先离线,然后再倒着做,第一个操作就成 ...

  4. LA 5031 Graph and Queries —— Treap名次树

    离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...

  5. [la P5031&hdu P3726] Graph and Queries

    [la P5031&hdu P3726] Graph and Queries Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: ...

  6. HDU 3726 Graph and Queries 平衡树+前向星+并查集+离线操作+逆向思维 数据结构大综合题

    Graph and Queries Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  7. HDU 3726 Graph and Queries (离线处理+splay tree)

    Graph and Queries Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  8. uvalive 5031 Graph and Queries 名次树+Treap

    题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...

  9. UVALive 5031 Graph and Queries (Treap)

    删除边的操作不容易实现,那么就先离线然后逆序来做. 逆序就变成了合并,用并存集判断连通,用Treap树来维护一个连通分量里的名次. Treap = Tree + Heap.用一个随机的优先级来平衡搜索 ...

随机推荐

  1. 计算机中位(bit), 字节(byte), 字(word)的关系

    1.位(bit) 来自英文bit,音译为“比特”,表示二进制位.位是计算机内部数据储存的最小单位,11010100是一个8位二进制数.一个二进制位只可以表示0和1两种状态(21):两个二进制位可以表示 ...

  2. VirtualBox中Ubuntu 14.04屏幕分辨率不能设置的问题

    VirtualBox中Ubuntu 14.04屏幕分辨率不能设置的问题   在VirtualBOx虚拟机中Ubuntu 14.04设置屏幕分辨率,怎么点都没反应. 方法一:安装与你的Ubuntu-Gu ...

  3. Ubuntu 14.04.4官方默认更新源sources.list

    Ubuntu 14.04.4官方默认更新源sources.list # deb cdrom:[Ubuntu LTS _Trusty Tahr_ - Release amd64 (20160217.1) ...

  4. Code[VS] 3123 高精度练习之超大整数乘法

    FFT 做 高精度乘法 #include <bits/stdc++.h> ); struct complex { double a, b; inline complex( , ) { a ...

  5. COGS396. [网络流24题]魔术球问题(简化版

    问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平 ...

  6. 对于angularJS的一点思考

    已经找好工作近两周了,入职基本上还算顺利,自己两年来的挑灯夜战也算是有了收获,于是这两周基本上是按部就班的工作,没有学习什么新技术.在上个公司的时候,同事在项目中使用angularJs,之前他也没有接 ...

  7. 触发器运用示例---laobai

    1 触发器 概念:trigger.逻辑对象的一种.当dml的增删改语句执行时,自动触发一系列动作. 分类:dml触发器.ddl触发器(很少见) sql:ddl,dml,dcl 按触发的时间分: 语句执 ...

  8. MlLib--逻辑回归笔记

    批量梯度下降的逻辑回归可以参考这篇文章:http://blog.csdn.net/pakko/article/details/37878837 看了一些Scala语法后,打算看看MlLib的机器学习算 ...

  9. js函数传参

    函数传参:重用代码,首先保持html代码相对一致,把核心主程序用函数包起来,把每组不同的值找出来,通过传参的方式减少代码的使用 下面代码是我早期练习的,大家随便看看就好 <!DOCTYPE ht ...

  10. PHP 过滤器

    PHP 过滤器 PHP 过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入. 什么是 PHP 过滤器? PHP 过滤器用于验证和过滤来自非安全来源的数据. 测试.验证和过滤用户输入或自定义数据是 ...