题目链接: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(时光倒流+名次树)的更多相关文章

  1. UVALive5031 Graph and Queries(Treap)

    反向操作,先求出最终状态,再反向操作. 然后就是Treap 的合并,求第K大值. #include<cstdio> #include<iostream> #include< ...

  2. UVa 1479 (Treap 名次树) Graph and Queries

    这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...

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

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

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

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

  5. HDU 3726 Graph and Queries treap树

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

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

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

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

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

  8. 时光倒流程序设计-AlloyTicker

    熵与负熵 熵遵循熵增原理,即无序非热能与热能之间的转换具有方向性.薛定谔说过:生命本质在于负熵.熵代表的是无序,负熵就是熵的对立,而负熵表示的则是有序.汲取负熵(米饭.面包.牛奶.鸡蛋),可以简单的理 ...

  9. Treap和名次树

    Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体.BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添 ...

随机推荐

  1. 层叠样式优先级CSS

    按照W3School网站(点这里直达)的说法,当同一个 HTML 元素被不止一个样式定义时,它们是有优先级之分的,如下,将优先级从小到大排列出来,其中4的优先级最高: 1.浏览器缺省设置2.外部样式表 ...

  2. Visual Studio中Js使用智能感知

    使用了第三方的JS库或框架,在VS中编写JS代码,发现真是个悲剧,完全只能手打,智能感知没了,这不符合VS的一贯做风只要在写代码的JS文件加上以下代码,就可以有智能感知了 ///<referen ...

  3. Android 5.0以上手机出现找不到so文件

    问题描述 最近做项目出了一个bug项目中用到so文件,在5.0以上的手机上会报一个初始化异常错误,并提示找不到so文件.lib里目录结构类似如下  在Android5以下都没有问题,在5.0以上会报错 ...

  4. Android四大组件之一:ContentProvider(内容提供者)

    Android中还提供了名为ContentProvider(内容提供者),可以向其他应用提供数据,但不常用,除非是同一公司开发的App,可以向不同应用提供数据.虽然为Android的四大组件之一,但用 ...

  5. 安卓工程修改包名后 Failed to find provider info for...问题

    安卓工程修改包名后 Failed to find provider info for com.android...provider问题 原因: 1. 多处含包名文件须同时更改 2. Manifest里 ...

  6. [总结]RTMP流媒体技术零基础学习方法

    本文主要总结一些我在学习RTMP流媒体技术过程中积累的经验.也为后来学习RTMP流媒体技术的人们一个参考.本文力图从简到难,循序渐进的介绍RTMP流媒体技术的方方面面,先从应用说起,逐步深化剖析相关工 ...

  7. (whh仅供自己参考)进行ip网络请求的步骤

    这个过程大致是这个样子: 1 添加通知 2 发送网络请求 里边有一个发送通知的操作 3 执行发送通知的具体操作 代码如下: 1 在VC添加通知 [[NSNotificationCenter defau ...

  8. 序列数据挖掘[ZZ]

    一.时间序列数据挖掘 时间序列是数据存在的特殊形式,序列的过去值会影响到将来值,这种影响的大小以及影响的方式可由时间序列中的趋势周期及非平稳等行为来刻画.一般来讲,时间序列数据都具有躁声.不稳定.随机 ...

  9. iPhone、iPad默认按钮样式问题

    iPhone.iPad默认按钮样式问题 解决方法给按钮元素添加一个-webkit-appearance: none;具体代码 input[type="button"], input ...

  10. python 时间戳

    import timeprint time.time()输出的结果是(单位:s):1395421406.39 x = time.localtime(x) x = time.strftime('%Y-% ...