题意:给你个点m条边的无向图,每个节点都有一个整数权值。你的任务是执行一系列操作。操作分为3种。。。

思路:本题一点要逆向来做,正向每次如果删边,复杂度太高。逆向到一定顺序的时候添加一条边更容易。详见算法指南P235。

 #include<cstdlib>

 struct Node
{
Node *ch[]; // 左右子树
int r; // 随机优先级
int v; // 值
int s; // 结点总数
Node(int v):v(v)
{
ch[] = ch[] = NULL;
r = rand();
s = ;
}
int cmp(int x) const
{
if (x == v) return -;
return x < v ? : ;
}
void maintain()
{
s = ;
if(ch[] != NULL) s += ch[]->s;
if(ch[] != NULL) s += ch[]->s;
}
}; void rotate(Node* &o, int d)
{
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 = (x < o->v ? : ); // 不要用cmp函数,因为可能会有相同结点
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);
int ret = ;
if(d == -)
{
Node* u = o;
if(o->ch[] != NULL && o->ch[] != NULL)
{
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();
} #include<cstdio>
#include<cstring>
#include<vector>
using namespace std; const int maxc = + ;
struct Command
{
char type;
int x, p; // 根据type, p代表k或者v
} commands[maxc]; const int maxn = + ;
const int maxm = + ;
int n, m, weight[maxn], from[maxm], to[maxm], removed[maxm]; // 并查集相关
int pa[maxn];
int findset(int x)
{
return pa[x] != x ? pa[x] = findset(pa[x]) : x;
} // 名次树相关
Node* root[maxn]; // Treap 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* &x)
{
if(x->ch[] != NULL) removetree(x->ch[]);
if(x->ch[] != NULL) removetree(x->ch[]);
delete x;
x = NULL;
} // 主程序相关
void add_edge(int x)
{
int u = findset(from[x]), v = findset(to[x]);
if(u != v)
{
if(root[u]->s < root[v]->s)
{
pa[u] = v;
mergeto(root[u], root[v]);
}
else
{
pa[v] = u;
mergeto(root[v], root[u]);
}
}
} int query_cnt;
long long query_tot;
void query(int x, int k)
{
query_cnt++;
query_tot += kth(root[findset(x)], k);
} void change_weight(int x, int v)
{
int u = findset(x);
remove(root[u], weight[x]);
insert(root[u], v);
weight[x] = v;
} int main()
{
int kase = ;
while(scanf("%d%d", &n, &m) == && n)
{
for(int i = ; i <= n; i++) scanf("%d", &weight[i]);
for(int i = ; i <= m; i++) scanf("%d%d", &from[i], &to[i]);
memset(removed, , sizeof(removed)); // 读命令
int c = ;
for(;;)
{
char type;
int x, p = , v = ;
scanf(" %c", &type);
if(type == 'E') break;
scanf("%d", &x);
if(type == 'D') removed[x] = ;
if(type == 'Q') scanf("%d", &p);
if(type == 'C')
{
scanf("%d", &v);
p = weight[x];
weight[x] = v;
}
commands[c++] = (Command)
{
type, x, p
};
} // 最终的图
for(int i = ; i <= n; i++)
{
pa[i] = i;
if(root[i] != NULL) removetree(root[i]);
root[i] = new Node(weight[i]);
}
for(int i = ; i <= m; i++) if(!removed[i]) add_edge(i); // 反向操作
query_tot = query_cnt = ;
for(int i = c-; i >= ; i--)
{
if(commands[i].type == 'D') add_edge(commands[i].x);
if(commands[i].type == 'Q') query(commands[i].x, commands[i].p);
if(commands[i].type == 'C') change_weight(commands[i].x, commands[i].p);
}
printf("Case %d: %.6lf\n", ++kase, query_tot / (double)query_cnt);
}
return ;
}

uvalive 5031 Graph and Queries 名次树+Treap的更多相关文章

  1. UVALive 5031 Graph and Queries (Treap)

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

  2. UVALive - 5031 Graph and Queries (并查集+平衡树/线段树)

    给定一个图,支持三种操作: 1.删除一条边 2.查询与x结点相连的第k大的结点 3.修改x结点的权值 解法:离线倒序操作,平衡树or线段树维护连通块中的所有结点信息,加个合并操作就行了. 感觉线段树要 ...

  3. UVaLive 5031 Graph and Queries (Treap)

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

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

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

  5. LA - 5031 - Graph and Queries

    题意:一个N个点(编号从1开始),M条边的无向图(编号从1开始),有3种操作: D X:把编号为X的边删了: Q X K:查询编号为X的结点所在连通分量第K大的元素: C X V:将编号为X的结点的权 ...

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

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

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

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

  8. HDU 3726 Graph and Queries treap树

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

  9. Treap和名次树

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

随机推荐

  1. 3.6 spring-construction-arg 子元素的使用与解析

    对于构造函数子元素是非常常用的. 相信大家也一定不陌生, 举个小例子: public class Animal { public String type; public int age; /** * ...

  2. 11个好用的jQuery拖拽拖放插件

    这次我们整理一些拖拽播放类型的jQuery插件,这些可能不是很常用,但偶尔会有网站设计项目用到,特别是后台相关的开发项目,这个拖放排序功能一般都会有,所以适合大家收藏起来,方便日后使用.接下来一起看盾 ...

  3. 团体程序设计天梯赛-练习集L1-001. Hello World

    L1-001. Hello World 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 这道超级简单的题目没有任何输入. 你只需要在一行中输 ...

  4. [Firefly引擎][学习笔记四][已完结]服务器端与客户端的通讯

    原地址:http://www.9miao.com/question-15-54981.html 传送门:学习笔记一学习笔记二学习笔记三 前言:学习笔记三是模块封装,这个在持续开发中会不断更新, 因为写 ...

  5. 想要上市,SaaS 企业应该重点关注什么?(下)

    前言:那些非常期待能在纳斯达克敲钟的 SaaS 服务提供商们,希望能从已经上市的「前辈」身上学到一些东西.对企业的销售主管来说,他们控制着影响整个公司长期收益的多个因素,同时,他们也对潜在投资者和金融 ...

  6. 解读Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)

    根据 src/corelib/global.h template <typename T>class QGlobalStatic{public: T *pointer; inline QG ...

  7. 115. Distinct Subsequences

    题目: Given a string S and a string T, count the number of distinct subsequences of T in S. A subseque ...

  8. itoa函数的实现(不同进制)

    2013-07-08 17:12:30 itoa函数相对于atoi函数,比较简单,还是要注意考虑的全面. 小结: 一下几点需要考虑: 对负数,要加上负号: 考虑不同进制,根据要求进行处理:对不同的进制 ...

  9. 【HDOJ】4601 Letter Tree

    挺有意思的一道题,思路肯定是将图转化为Trie树,这样可以求得字典序.然后,按照trie的层次求解.一直wa的原因在于将树转化为线性数据结构时要从原树遍历,从trie遍历就会wa.不同结点可能映射为t ...

  10. hdu4635Strongly connected

    http://acm.hdu.edu.cn/showproblem.php?pid=4635 tarjan缩点 统计缩点后每个结点的出度入度 将那个包含原来点数最少的 且出度或者入度为0的大节点看作一 ...