UVaLive5031 Graph and Queries(时光倒流+名次树)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332
【思路】
时光倒流+名次树(rank tree)。
所谓“时光倒流”即逆向处理,因为D删除边并不好操作所以我们倒着处理,删除边转化为添加边,C转化为将weight变回操作前的数,Q不变。
名次树实现以上操作:名次树是Treap+s域实现的,可以提供kth即查询第k大的数的操作和Treap的所有功能。
1)对于D(x):合并from[x]与to[x]所在的rank tree,后序思想,将src中的结点逐个添加到dest中,采用启发式合并。
2)对于Q(x,k):调用kth操作同时累计cnt与tot。
3)对于C(x,v):调用一次romove(root[findset(x)],weight[x]),再调用一次insert(root[findset(x)],v)。
用到一个并查集快速寻找x所属rank tree的根。
【代码】
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<iostream>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; const int maxn = +;
//Treap相关
struct Node{
Node *ch[];
int r,v,s; //r为优先级 v为键值 s为结点总数
Node(int w) :v(w) { ch[]=ch[]=NULL; s=; r=rand(); }
int cmp(int x) const{ //x应在左子树d=0 x应在右子树d=1
if(x==v) return -;
return x<v? :;
}
int cmp2(int x) const{ return x<v? :; }
void maintain() { //名次树维护 s
s=;
if(ch[]!=NULL) s+=ch[]->s;
if(ch[]!=NULL) s+=ch[]->s;
}
};
void rotate(Node* &o,int d) { //旋转操作 d=0左旋d=1右旋
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=o->cmp2(x); //可能会有键值相等的结点
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==-) {
Node *u=o;
if(o->ch[]!=NULL && o->ch[]!=NULL){ //根据左右子[优先级]旋转 旋转后递归删除x
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) { //返回第k[大]的数
if(o==NULL || k<= || k>o->s) 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-);
}
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;
}
//并查集相关
int pa[maxn];
int findset(int u) { return u==pa[u]? u:pa[u]=findset(pa[u]); }
//题目相关
Node* root[maxn];
int weight[maxn],from[maxn],to[maxn];
bool removed[maxn];
int n,m,cnt,kase;
long long sum;
struct Command{ char type; int a,b;
};
vector<Command> cs; void addedge(int i) {
int u=findset(from[i]),v=findset(to[i]);
if(u!=v) {
if(root[u]->s > root[v]->s) { pa[v]=u; mergeto(root[v],root[u]); }
else { pa[u]=v; mergeto(root[u],root[v]); }
}
}
void query(int x,int k) {
cnt++;
sum+=kth(root[findset(x)],k);
}
void changeWeight(int x,int p) {
int u=findset(x);
remove(root[u],weight[x]);
insert(root[u],p);
weight[x]=p;
} int main() {
srand(time()); //初始化随机数种子
kase=;
while(scanf("%d%d",&n,&m)== && (n&&m)) {
FOR(i,,n) scanf("%d",&weight[i]);
FOR(i,,m) scanf("%d%d",&from[i],&to[i]);
char type;
memset(removed,,sizeof(removed));
cs.clear();
while(scanf(" %c",&type)== && type!='E') {
int x=,p=;
scanf("%d",&x);
if(type=='D') removed[x]=;
if(type=='Q') scanf("%d",&p);
if(type=='C') {
scanf("%d",&p);
swap(p,weight[x]);
}
cs.push_back((Command){type,x,p});
}
FOR(i,,n) {
pa[i]=i; if(root[i]!=NULL) removetree(root[i]);
root[i]=new Node(weight[i]);
}
FOR(i,,m) if(!removed[i]) addedge(i);
int d=cs.size(); sum=cnt=;
for(int i=d-;i>=;i--) {
if(cs[i].type=='D') addedge(cs[i].a);
if(cs[i].type=='Q') query(cs[i].a,cs[i].b);
if(cs[i].type=='C') changeWeight(cs[i].a,cs[i].b);
}
printf("Case %d: %.6lf\n",++kase,sum/(double)cnt);
}
return ;
}
UVaLive5031 Graph and Queries(时光倒流+名次树)的更多相关文章
- UVALive5031 Graph and Queries(Treap)
反向操作,先求出最终状态,再反向操作. 然后就是Treap 的合并,求第K大值. #include<cstdio> #include<iostream> #include< ...
- UVa 1479 (Treap 名次树) Graph and Queries
这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...
- uvalive 5031 Graph and Queries 名次树+Treap
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...
- LA 5031 Graph and Queries —— Treap名次树
离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...
- HDU 3726 Graph and Queries treap树
题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring ...
- [la P5031&hdu P3726] Graph and Queries
[la P5031&hdu P3726] Graph and Queries Time Limit: 10000/5000 MS (Java/Others) Memory Limit: ...
- HDU 3726 Graph and Queries 平衡树+前向星+并查集+离线操作+逆向思维 数据结构大综合题
Graph and Queries Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- 时光倒流程序设计-AlloyTicker
熵与负熵 熵遵循熵增原理,即无序非热能与热能之间的转换具有方向性.薛定谔说过:生命本质在于负熵.熵代表的是无序,负熵就是熵的对立,而负熵表示的则是有序.汲取负熵(米饭.面包.牛奶.鸡蛋),可以简单的理 ...
- Treap和名次树
Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体.BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添 ...
随机推荐
- 我的博客css得到别人的认可
你好 在吗?? 本消息来自QQ临时会话,如果您收到骚扰信息,可点击以下网址中的"停用服务"关闭临时会话: http://shang.qq.com/widget/set.php 20 ...
- 关于Entity Framework 5 从数据库生成模型时没有字段注释的解决方法!
目前用到了EF5进行模型创建,发现从数据库生成过来的实体中并没有包含字段的说明信息(鄙视下微软,这么简单的问题都不给解决下,太粗枝大叶了),网上找到了EFTSQLDocumentation.Gener ...
- Android开发手记(32) 使用摄像头拍照
在Android中,使用摄像头拍照一般有两种方法, 一种是调用系统自带的Camera,另一种是自己写一个摄像的界面. 我们要添加如下权限: <uses-permission android:na ...
- mysql - 初探
1,查询所有数据库名称: show databases; 2,查询所有表: use database_name; show tables; 3,查询表中的所有字段: desc table_name;
- Java设计模式(学习整理)---工厂模式
1.工厂模式 1.1 为什么使用工厂模式? 因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时 ...
- 数据挖掘相关的10个问题[ZZ]
NO.1 Data Mining 和统计分析有什么不同? 硬要去区分Data Mining和Statistics的差异其实是没有太大意义的.一般将之定义为Data Mining技术的CART.CHAI ...
- busybox下mount nfs的命令
busybox下mount nfs的命令 mount -f nfs -o nolock 10.130.30.2:/nfs/nuc970/rootfs /mnt/test
- Eclipse 编译StanfordNLP
1.源码最新下载地址:http://nlp.stanford.edu/software/index.shtml; 2.解压stanford-corenlp.zip; 3.打开Eclipse新建JAVA ...
- js浏览器键盘事件控制(转自新浪微博)
js键盘事件全面控制 主要分四个部分第一部分:浏览器的按键事件第二部分:兼容浏览器第三部分:代码实现和优化第四部分:总结 第一部分:浏览器的按键事件 用js实现键盘记录,要关注浏览器的三种按键事件类型 ...
- 模块化编程AMD&CommonJS
为什么要模块化编程 如果JS也可以像类似python,Java使用import,引入我们想要的模块,想要什么模块,就加载什么模块,可以给前端编程带来更多的便捷,结构更加清晰明了.但是,这样做有一个前提 ...