题意:

  给一个无向图,再给一系列操作(以下3种),输出最后的平均查询结果。

(1)D X 删除第x条边。

(2)Q X k  查询与点X相连的连通分量中第k大的点的权值。

(3)C X v  将点X的权值改为v。

思路:

  第一点,由于需要删除边,不是很方便,所以可以先将所有操作存起来,反序来操作,这样删边就变成加边,方便了不少。每次加边时若两点不属于同个连通分量,就将点少的整个连通分量中的点逐个插入到另一个连通分量中。

  第二点,查第k大,这个比较简单,只需要维护Treap上每个点的的左右孩子数量就可以了。查的只是某个点所属连通分量中的第k大值,与真实图是怎样的无关。

  第三点,改权值,这个麻烦。可以先删除该点,再插入改过权的该点。删除方式就是将该点旋转到成为叶子,然后删除它就方便了,因为还需要维护堆的性质,所以往下旋转比较方便的。

坑点:随时要注意更新每个连通分量的根节点,也就是说必须用引用的时候,尽量用引用。在第一点操作时,需要插很多点,每插1个点都可能成为根,所以要随时更新根节点。

 #include <bits/stdc++.h>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
bool single[N];
int w[N], from[N*], to[N*], cut[N*], pre[N], root[N];
struct opera
{
char type;
int a, b;
opera(char t,int a,int b):type(t),a(a),b(b){};
};
deque<opera> que;
struct node //Treap
{
int val, pre, rank; //ran是优先级
int ch[], son[];
node(){};
node(int val):val(val)
{
rank=rand();
ch[]=ch[]=son[]=son[]=pre=;
};
}nod[N]; int find(int x){return pre[x]==x? x: pre[x]=find(pre[x]);} int Query(int t,int k) //找第k大
{
if( k< || nod[t].son[] + nod[t].son[] + < k) return ; //k太小or太大
if( nod[t].son[]==k- ) return nod[t].val;
if( nod[t].son[]>k- ) return Query(nod[t].ch[], k);
else return Query(nod[t].ch[], k-nod[t].son[]-);
} void Rotate(int t, int d) //d为方向,0是左旋,1是右
{
int far=nod[t].pre;
int son=nod[t].ch[d]; //far的孩子
int gra=nod[far].pre; //far的父亲 nod[son].pre=far;
nod[t].pre=gra;
nod[far].pre=t; nod[far].ch[d^]=son;
nod[t].ch[d]=far;
nod[gra].ch[nod[gra].ch[]==far]=t; //子树中的节点要更新
nod[far].son[d^]=nod[t].son[d];
nod[t].son[d]+=+nod[far].son[d]; //别忘了还有far也是个节点 if(gra==) root[find(far)]=t; //更新连通分量的根节点
} int get_child(int t) //返回孩子编号,总是返回rank较大的那个。0表示无孩子
{
if(!nod[t].ch[] && !nod[t].ch[]) return ;
if(nod[t].ch[] && nod[t].ch[])
{
int L=nod[t].ch[], R=nod[t].ch[];
if(nod[L].rank < nod[R].rank) return R;
else return L;
}
if(nod[t].ch[]) return nod[t].ch[];
else return nod[t].ch[];
} void Insert(int root,int t) //将t插入到root中
{
if(nod[t].val<nod[root].val)
{
nod[root].son[]++;
if(nod[root].ch[]) Insert(nod[root].ch[], t);
else nod[root].ch[]=t, nod[t].pre=root;
}
else
{
nod[root].son[]++;
if(nod[root].ch[]) Insert(nod[root].ch[], t);
else nod[root].ch[]=t, nod[t].pre=root;
}
int son=nod[root].ch[];
if( nod[son].rank > nod[root].rank ) Rotate(son, ); //孩子的rank比我还大
}
void clear(int t,int v) //清空点t,值改为v
{
nod[t].pre=nod[t].ch[]=nod[t].ch[]=nod[t].son[]=nod[t].son[]=;
nod[t].val=v;
} void Merge(int &root, int t) //递归将t中的节点逐个拆出
{
if(nod[t].ch[]>) Merge(root, nod[t].ch[]);
if(nod[t].ch[]>) Merge(root, nod[t].ch[]);
clear(t, nod[t].val); //值仍不变
single[root]=; //非单身了
single[t]=;
Insert(root, t); //将t插入到root中
} void add_edge(int i)
{
int u=find(from[i]), v=find(to[i]); //两点所在连通分量
if(u!=v) //这里也会去掉重边
{
int &uu=root[u], &vv=root[v]; //找到连通分量的树根。注意:必须是引用,有可能每插一次就换根了。
if( nod[uu].son[]+nod[uu].son[] < nod[vv].son[]+nod[vv].son[]) //uu小
pre[u]=v, Merge(vv, uu); //uu拆出来装到vv上面去
else
pre[v]=u, Merge(uu, vv);
}
} void change(int t,int v) //将t的权值改为v
{
if(single[t]==true){nod[t].val=v;return ;} //仅有1个点,直接改
int far, son, tmp;
while( (son=get_child(t))!= ) Rotate( son, nod[t].ch[]==son); //先把t转到底端
tmp=t;
while( nod[tmp].pre!= ) //调整到根节点的孩子数量,沿途减1。
{
far=nod[tmp].pre;
nod[far].son[nod[far].ch[]==tmp]--;
tmp=far;
}
far=nod[t].pre;
nod[far].ch[ nod[far].ch[]==t ]=; //需要做的只是改变父亲的孩子指针。
clear(t, v);
Insert(root[find(t)], t); //改完值插到root中。
} double cal(int n,int m)
{
for(int i=; i<=n; i++) pre[i]=root[i]=i,nod[i]=node(w[i]); //初始时,root和连通分量编号都是自己
for(int i=; i<=m; i++) if(cut[i]==) add_edge(i);
LL ans=, cnt=;
while(!que.empty())
{
opera p=que.front();que.pop_front();
if(p.type=='D') add_edge(p.a); //加边
if(p.type=='Q') cnt++,ans+=Query(root[find(p.a)], p.b);
if(p.type=='C') change(p.a, p.b); //改权值
}
return ans/(double)cnt;
} int main()
{
freopen("input.txt", "r", stdin);
int a, b, c, n, m, Case=;
char op;
while(cin>>n>>m, n+m)
{
memset(single, , sizeof(single));
memset(cut, , sizeof(cut));
for(int i=; i<=n; i++) scanf("%d", &w[i]);
for(int i=; i<=m; i++) scanf("%d %d", &from[i], &to[i]); while(cin>>op,op!='E')
{
if(op=='D'){scanf("%d",&a);cut[a]=;} //删边
if(op=='Q') scanf("%d%d",&a,&b); //查询
if(op=='C'){scanf("%d%d",&a,&b),swap(w[a], b);} //改权
que.push_front(opera(op, a, b));
}
printf("Case %d: %.6f\n", ++Case, cal(n, m));
}
return ;
}

AC代码

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

  1. UVALive 5031 Graph and Queries (Treap)

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

  2. HDU 3726 Graph and Queries(平衡二叉树)(2010 Asia Tianjin Regional Contest)

    Description You are given an undirected graph with N vertexes and M edges. Every vertex in this grap ...

  3. uva 1153 顾客是上帝(贪心)

    uva 1153 顾客是上帝(贪心) 有n个工作,已知每个工作需要的时间q[i]和截止时间d[i](必须在此前完成),最多能完成多少个工作?工作只能串行完成,第一项任务开始的时间不早于时刻0. 这道题 ...

  4. 2021.12.07 P4291 [HAOI2008]排名系统(Treap)

    2021.12.07 P4291 [HAOI2008]排名系统(Treap) https://www.luogu.com.cn/problem/P4291 双倍经验: https://www.luog ...

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

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

  6. 洛谷P3369普通平衡树(Treap)

    题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...

  7. 树堆(Treap)

    平衡树 简介: 平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.平衡二叉树的常用实现方 ...

  8. 普通平衡树(treap)

    题干:6种操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最小的排名) 4. 查询排名为x的数 5. 求x的前驱(前驱定义为小于 ...

  9. 树堆(Treap)学习笔记 2020.8.12

    如果一棵二叉排序树的节点插入的顺序是随机的,那么这样建立的二叉排序树在大多数情况下是平衡的,可以证明,其高度期望值为 \(O( \log_2 n )\).即使存在一些极端情况,但是这种情况发生的概率很 ...

随机推荐

  1. macbook pro 下eclipse配置svn插件

    eclipse中最常使用的SVN插件是subclipse,先到subclipse官网:http://subclipse.tigris.org下载该插件.   如上图,点击“Download and I ...

  2. iOS 中的 Block

    参考:链接 (1)block作为本地变量(local variable) returnType (^blockName)(parameterTypes) = ^returnType(parameter ...

  3. 018--python 函数参数、变量、前向引用、递归

    目录 一.python函数的定义 二.函数参数 三.全局变量和局部变量 四.前向引用 五.递归 一.python函数的定义 python函数是对程序逻辑进行结构化或过程化的一种方法 1 python中 ...

  4. (水题)洛谷 - P1003 - 铺地毯

    https://www.luogu.org/problemnew/show/P1003 一开始觉得是用树套树来区间修改单点查询,但是发现空间不够开. 看了题解发现这个是静态的问题,而且只问一个点的结果 ...

  5. 洛谷 - P1309 - 瑞士轮 - 归并排序

    https://www.luogu.org/problemnew/show/P1309 一开始写的直接快排没想到真的TLE了. 想到每次比赛每个人前移的量不会很多,但是不知从哪里开始优化. 搜索一下原 ...

  6. (水题)洛谷 - P1579 - 哥德巴赫猜想(升级版)

    https://www.luogu.org/problemnew/show/P1579 先预处理出素数看看有多少个,大概才2500个不到(事实上素数的个数大约是 $\frac{n}{ln(n)}$ ) ...

  7. 如何正确访问Redis中的海量数据?服务才不会挂掉!

    一.前言 有时候我们需要知道线上的Redis的使用情况,尤其需要知道一些前缀的key值,让我们怎么去查看呢?并且通常情况下Redis里的数据都是海量的,那么我们访问Redis中的海量数据?如何避免事故 ...

  8. The local variable fruit may not have been initialized 错误

    eclipse错误提示如图: 错误代码如图: 首先这错误的翻译是:局部变量"水果"尚未初始化,所以对象该如何初始化呢,我百度之后找到了答案,修改过后如下图所示. 这个错误的问题所在 ...

  9. jvm 实战

    https://blog.csdn.net/neutrojan/article/details/50532590# 1.ps -ef |grep java 找出最耗性能的JAVA进程2.top -Hp ...

  10. _bzoj1911 [Apio2010]特别行动队【斜率优化dp】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 裸的斜率优化dp. #include <cstdio> const int ...