离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1logn2),由于合并之后原本结点数少的子树结点数至少翻倍,所以每个结点最多被插入 logn 次,故总时间复杂度为 O(n log2n)  . 注意细节处理,代码如下: #include <cstdio> #include <cstdlib> #include <cstring>…
题意:一个N个点(编号从1开始),M条边的无向图(编号从1开始),有3种操作: D X:把编号为X的边删了: Q X K:查询编号为X的结点所在连通分量第K大的元素: C X V:将编号为X的结点的权值修改为V. 问所有查询的结果的平均值(1 <= N <= 20000, 0 <= M <= 60000, -10^6 <= 点权 <= 10^6, 1 <= Q操作次数 <= 2 * 10^5, C操作次数 <= 2 * 10^5). 题目链接:http…
题意:初始时给出一个图,每个点有一个权值,三种操作:(1)删除某个边:(2)修改每个点的权值:(3)询问与节点x在一个连通分量中所有点的第K大的权值. 析:首先是要先离线,然后再倒着做,第一个操作就成了加边操作,很容易实现,第二操作,就是分成两个操作,先把x结点删掉,然后再插入一个新结点, 最后一个是就是求某个连通分量的第 k 大,直接用treap直接查找就好,注意问是第 k 大,不是第 k 小. 代码如下: #pragma comment(linker, "/STACK:1024000000,…
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见算法指南P235. #include<cstdlib> struct Node { Node *ch[]; // 左右子树 int r; // 随机优先级 int v; // 值 int s; // 结点总数 Node(int v):v(v) { ch[] = ch[] = NULL; r = r…
这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个连通分量. 由于图中添边比较方便,用并查集来表示连通分量就好了,但是删边不太容易实现. 所以,先把所有的边删去,然后逆序执行命令.当然,C命令也要发生一些变化,比如说顺序的情况是从a变成b,那么逆序执行的话应该就是从b变成a. 最后两棵树的合并就是启发式合并,把节点数少的数并到节点数多的数里去. #…
题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct Node { Node *ch[2]; int r; int v; int s; Node(int v): v(v) { ch[0] = ch[1] = NULL; r = rand(); s…
Treap实现名次树 前言 学平衡树的过程可以说是相当艰难.浏览Blog的过程中看到大量指针版平衡树,不擅长指针操作的我已经接近崩溃.于是,我想着一定要写一篇非指针实现的Treap的Blog. 具体如下. 简介 Treap(树堆,Tree+Heap)是一种强大的数据结构--每个节点除了本身键值(v)之外,附有一个随机优先级(p),其中v满足二叉搜索树性质,p满足堆性质(下文中为大根堆),通过旋转操作来维护性质,并使整棵树保持平衡. 名次树 顾名思义就是可以查找x的排名.查找第x名的值.查找前驱与…
删除边的操作不容易实现,那么就先离线然后逆序来做. 逆序就变成了合并,用并存集判断连通,用Treap树来维护一个连通分量里的名次. Treap = Tree + Heap.用一个随机的优先级来平衡搜索树. 名次查询需要维护树的结点数量,假设当前在u点,u的左子树有n个结点,那么u的就是以u为根的树上第n+1小的. 如果查询的不是n+1,那么根据结点数量判断一下在哪颗子树上,然后去查询. 树的合并就将结点数少的树上的点往结点数多的树里面插,然后删掉结点少的树. 修改权值就分解成删除点和插点. 写的…
给定一个图,支持三种操作: 1.删除一条边 2.查询与x结点相连的第k大的结点 3.修改x结点的权值 解法:离线倒序操作,平衡树or线段树维护连通块中的所有结点信息,加个合并操作就行了. 感觉线段树要好写很多. 平衡树(Treap)版: #include<bits/stdc++.h> typedef long long ll; using namespace std; ; struct E { int u,v; } e[N]; int a[N],faz[N],n,m,del[N]; int f…
反向操作,先求出最终状态,再反向操作. 然后就是Treap 的合并,求第K大值. #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<vector> #inc…