\[\text{Preface}
\]

算是一道思维难度稍易,代码难度稍难的题吧。

\[\text{Description}
\]

给出一张 \(n\) 个点,\(m\) 条边的图,点带权。需要支持三个操作:

  • D x 删掉编号为 \(x\) 的边
  • Q x k 查询与节点 \(x\) 联通的所有节点中,点权第 \(k\) 大节点的点权
  • C x v 将节点 \(x\) 点权改为 \(v\)

多组数据,每组数据最终需要输出所有查询的平均值 ( 保留 6 位 ) ,没有强制在线。

\[\text{Solution}
\]

不知道大家有没有做过 这道题 ,推荐先去做一下。

\(~\)

首先,对于同一个连通块里的所有节点,查询与任意一个节点连通的所有节点的第 \(k\) 大,都是查询该连通块里所有节点的第 \(k\) 大。已经很明显可以用并查集维护每个连通块的代表节点,再在这个代表节点上用一个数据结构维护连通块信息,支持合并,查询第 \(k\) 大。

我们发现权值线段树可以做到上述操作,尝试用权值线段树维护,每个节点开一个权值线段树。

\(~\)

对于操作 Q x k \(:\)

​ ​ ​ ​ 权值线段树基本操作。

对于操作 C x v \(:\)

​​ ​ ​ ​ 我们可以看作是在 \(x\) 这个位置上少了一个原来的点权,再多了一个新的点权,两次插入操作即可解决。

对于操作 D x \(:\)

​ ​ ​ ​ \(......\) ,我们发现删掉一条边,不能有效使得一个连通块分裂成两个连通块,并且维护权值线段树。

\(~\)

注意到此题 没有强制在线 ,意味着,我们可以离线地把所有操作都读进来,然后去反着考虑这些询问。

这样一来,D x 操作就可以变为 \(:\) 加入一条编号为 \(x\) 的边。其余的两个操作不变。

我们发现添加一条边很容易维护 \(:\) 找出 \(u,v\) 所在的连通块 \(p,q\) ,若 \(p=q\) ,则无需操作;否则合并权值线段树 \(p\) 和权值线段树 \(q\) ,然后令 \(fa[q]=p\) 。

综上所述,我们就可以用 权值线段树 \(+\) 并查集 解决本题了。\((\) 当然什么 \(splay\),\(treap\) 启发式合并也行 \()\)

时空复杂度 \(\text{O(n log n)}\) 。

\[\text{Code}
\]

  1. #include<cstdio>
  2. #include<cstring>
  3. #define RI register int
  4. using namespace std;
  5. inline int read()
  6. {
  7. int x=0,f=1;char s=getchar();
  8. while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
  9. while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
  10. return x*f;
  11. }
  12. const int N=6000100,M=6000100,Q=6000100,MLOGN=50000000;
  13. const int INF=1e6;
  14. int T;
  15. int n,m,q;
  16. int cnt;
  17. long double ans;
  18. int val[N];
  19. struct Edge{
  20. int u;
  21. int v;
  22. bool del;
  23. }e[M];
  24. char opt[Q];
  25. int x[Q],k[Q];
  26. int fa[N];
  27. int get(int x)
  28. {
  29. if(fa[x]==x)return x;
  30. return fa[x]=get(fa[x]);
  31. }
  32. int tot,root[N];
  33. struct SegmentTree{
  34. int lc,rc;
  35. int cnt;
  36. }t[MLOGN];
  37. int New()
  38. {
  39. tot++;
  40. t[tot].lc=t[tot].rc=t[tot].cnt=0;
  41. return tot;
  42. }
  43. void insert(int &p,int l,int r,int delta,int val)
  44. {
  45. if(!p)
  46. p=New();
  47. t[p].cnt+=val;
  48. if(l==r)return;
  49. int mid=(l+r)>>1;
  50. if(delta<=mid)
  51. insert(t[p].lc,l,mid,delta,val);
  52. else
  53. insert(t[p].rc,mid+1,r,delta,val);
  54. }
  55. int merge(int p,int q)
  56. {
  57. if(!p||!q)
  58. return p^q;
  59. t[p].cnt+=t[q].cnt;
  60. t[p].lc=merge(t[p].lc,t[q].lc);
  61. t[p].rc=merge(t[p].rc,t[q].rc);
  62. return p;
  63. }
  64. int ask(int p,int l,int r,int k)
  65. {
  66. if(l==r)
  67. return l;
  68. int mid=(l+r)>>1;
  69. int rcnt=t[t[p].rc].cnt;
  70. if(k<=rcnt)
  71. return ask(t[p].rc,mid+1,r,k);
  72. else
  73. return ask(t[p].lc,l,mid,k-rcnt);
  74. }
  75. void link(int u,int v)
  76. {
  77. u=get(u),v=get(v);
  78. if(u==v)return;
  79. root[u]=merge(root[u],root[v]);
  80. fa[v]=u;
  81. }
  82. void work()
  83. {
  84. tot=cnt=ans=q=0;
  85. memset(root,0,sizeof(root));
  86. for(RI i=1;i<=n;i++)
  87. val[i]=read();
  88. for(RI i=1;i<=m;i++)
  89. e[i].u=read(),e[i].v=read();
  90. char tmp[2];
  91. while(scanf("%s",tmp),tmp[0]!='E')
  92. {
  93. opt[++q]=tmp[0];
  94. switch(tmp[0])
  95. {
  96. case 'D':{
  97. x[q]=read();
  98. e[x[q]].del=true;
  99. break;
  100. }
  101. case 'Q':{
  102. x[q]=read(),k[q]=read();
  103. cnt++;
  104. break;
  105. }
  106. case 'C':{
  107. x[q]=read(),k[q]=val[x[q]],val[x[q]]=read();
  108. break;
  109. }
  110. }
  111. }
  112. for(RI i=1;i<=n;i++)
  113. fa[i]=i,insert(root[i],-INF,INF,val[i],1);
  114. for(RI i=1;i<=m;i++)
  115. {
  116. if(e[i].del)continue;
  117. link(e[i].u,e[i].v);
  118. }
  119. for(RI i=q;i>=1;i--)
  120. switch(opt[i])
  121. {
  122. case 'D':{
  123. e[x[i]].del=false;
  124. link(e[x[i]].u,e[x[i]].v);
  125. break;
  126. }
  127. case 'Q':{
  128. int p=get(x[i]);
  129. int A=ask(root[p],-INF,INF,k[i]);
  130. if(A==-INF||A==INF)
  131. continue;
  132. ans+=(long double)A/cnt;
  133. break;
  134. }
  135. case 'C':{
  136. int p=get(x[i]);
  137. insert(root[p],-INF,INF,val[x[i]],-1);
  138. val[x[i]]=k[i];
  139. insert(root[p],-INF,INF,val[x[i]],1);
  140. break;
  141. }
  142. }
  143. printf("Case %d: %Lf\n",++T,ans);
  144. }
  145. int main()
  146. {
  147. while(n=read(),m=read(),n&&m) work();
  148. return 0;
  149. }

\[\text{Thanks} \ \text{for} \ \text{watching}
\]

题解 UVA1479 【Graph and Queries】的更多相关文章

  1. UVA1479 Graph and Queries

    思路 恶心人的题目 还是类似永无乡一题的Treap启发式合并思路 但是由于加边变成了删边 所以应该离线后倒序处理 数组要开够 代码 #include <cstdio> #include & ...

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

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

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

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

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

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

  5. HDU 3726 Graph and Queries treap树

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

  6. 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 ...

  7. CF1416D Graph and Queries

    本题解用于作者加深算法印象,也欢迎各位的阅读. 题目大意 给你一张无向图,并给你两种操作: \(1~v\) :找到当前点 \(v\) 所在的联通块内权值最大的点,输出该点权值并将其权值改为 \(0\) ...

  8. UVALive5031 Graph and Queries(Treap)

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

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

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

随机推荐

  1. mysql-5.7.9-winx64遇坑记

    昨天在mysql5.0上导入sql文件时,一直卡在一个地方报错,也没仔细分析,认为应该是mysql版本太低不支持这个语法而已.遂决心下载一个最新版本的mysql,却浑然不知前面无数的坑已经埋伏好了在等 ...

  2. Android Studio build不显示Generate signed apk问题

    如果是刚装的AS,那么新建一个项目,进入项目后,会发现build选项卡缺了一些选项,同时底部sync在转圈圈,其实是AS在自动下载gradle,也许还在下载build-tools,我等了11分钟才结束 ...

  3. 你还不会Git?那就不要写代码了(一)

    Git应用开发学习 如果你还不会使用Git,那就不要写代码了. 一旦你会使用了Git,就再也不想使用SVN了.永远也回不去了. Mac上使用Git,肯定离不开对Mac上的操作.就要使用常用的Linux ...

  4. 暑假提高组集训Day1 T1

    说实话,今天的题真的有点难! ~备受打击~ 我们先来看一看第一题吧 看起来好像不太简单,其实并不难 下面来提供两种方法吧 1.做法一 //签到题 /* 那么这一题就是告诉你n个点的坐标,把它们分别放到 ...

  5. poi解析excel(含有公式)

    /** * Jun 25, 2012 */ import java.io.File; import java.io.FileInputStream; import java.io.IOExceptio ...

  6. gitbub 基本使用

    一.环境 git:https://git-scm.com/ 申请github账号:https://github.com/ 二.安装git 一直next即可 三.创储存建库 1.选择New reposi ...

  7. oa办公系统是什么?对企业有什么作用?

    OA办公系统是指利用计算机网络帮助企业实现办公自动化,用系统软件代替传统的手工工作帮助企业处理内部事务,例如文档共享.部门协作.报销.业务流程等等,最终目的帮助企业提高工作效率,实现利益最大化. 随着 ...

  8. Asp.Net Core 3.1 Api 集成Abp项目依赖注入

    Abp 框架 地址https://aspnetboilerplate.com/ 我们下面来看如何在自己的项目中集成abp的功能 我们新建core 3.1 API项目和一个core类库 然后 两个项目都 ...

  9. 这个时候 快下班了 我来翻译一段: Pro ASP.NET MVC 3 Framework

    Binding to a Derived Type绑定派生类型Although we have focused on interfaces (since that is most relevant i ...

  10. Python学习,第四课 - 字符串相关操作

    这次主要说说Python中字符串的使用方法详解 capitalize 首字母大写 print('chengshou'.capitalize()) #输出结果:Chengshou title 修改成标题 ...