题目传送门

棘手的操作

题目描述

有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:

  • U x y: 加一条边,连接第x个节点和第y个节点
  • A1 x v: 将第x个节点的权值增加v
  • A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v
  • A3 v: 将所有节点的权值都增加v
  • F1 x: 输出第x个节点当前的权值
  • F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值
  • F3: 输出所有节点中,权值最大的节点的权值

输入输出格式

输入格式:

输入的第一行是一个整数N,代表节点个数。接下来一行输入N个整数,a[1], a[2], ..., a[N],代表N个节点的初始权值。再下一行输入一个整数Q,代表接下来的操作数。最后输入Q行,每行的格式如题目描述所示。

输出格式:

对于操作F1, F2, F3,输出对应的结果,每个结果占一行。

输入输出样例

输入样例#1:

  1. 3
  2. 0 0 0
  3. 8
  4. A1 3 -20
  5. A1 2 20
  6. U 1 3
  7. A2 1 10
  8. F1 3
  9. F2 3
  10. A3 -10
  11. F3
输出样例#1:

  1. -10
  2. 10
  3. 10

说明

对于30%的数据,保证 N<=100,Q<=10000

对于80%的数据,保证 N<=100000,Q<=100000

对于100%的数据,保证 N<=300000,Q<=300000

对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], ..., a[N]<=1000


  分析:

  真是一道恶心的左偏树题。

  需要维护两个左偏树,第一个维护正常的操作信息,第二个维护所有点中的最大值。

  第一种操作:在第一个左偏树中$merge$即可,另外有一个小优化,合并的两个堆顶中较小的一个可以直接从第二个左偏树中删除(正确性自己思考)。

  第二种操作:将该点从两个左偏树中删除,修改值以后再重新放回去。

  第三种操作:用$lazy$标记,只修改堆顶的值,后面再$merge$或者删除节点的时候下方标记。

  第四种操作:用一个变量记录,需要输出的时候再加上。

  第五种操作:直接输出第一个左偏树中该节点的值。

  第六种操作:直接输出第一个左偏树中该节点所在堆的堆顶的值。

  第七种操作:直接输出第二个左偏树的根节点的值。

  以上。

  题如其名,真$TM$又棘手又恶心。。。

  Code:

  1. //It is made by HolseLee on 28th Aug 2018
  2. //Luogu.org P3273
  3. #include<queue>
  4. #include<cstdio>
  5. #include<cstring>
  6. #include<iostream>
  7. #include<algorithm>
  8. #define Max(a,b) (a)>(b) ? (a) : (b)
  9. using namespace std;
  10.  
  11. const int N=3e5+;
  12. int n,a[N],m,allsign,root;
  13. struct Leftist{
  14. int ch[N][],val[N],sign[N],fa[N],dis[N];
  15.  
  16. void clear(int x)
  17. {
  18. ch[x][]=ch[x][]=fa[x]=;
  19. }
  20.  
  21. int sum(int x)
  22. {
  23. int ret=;
  24. while(x=fa[x])ret+=sign[x];
  25. return ret;
  26. }
  27.  
  28. void pushdown(int x)
  29. {
  30. int ul=ch[x][], ur=ch[x][];
  31. if( ul )val[ul]+=sign[x], sign[ul]+=sign[x];
  32. if( ur )val[ur]+=sign[x], sign[ur]+=sign[x];
  33. sign[x]=;
  34. }
  35.  
  36. int merge(int x,int y)
  37. {
  38. if(!x||!y)return x+y;
  39. if( val[x]<val[y] )
  40. swap(x,y);
  41. pushdown(x);
  42. int &ul=ch[x][], &ur=ch[x][];
  43. ur=merge(ur,y); fa[ur]=x;
  44. if( dis[ur]>dis[ul] )swap(ul,ur);
  45. dis[x]=dis[ur]+;
  46. return x;
  47. }
  48.  
  49. int find(int x)
  50. {
  51. while(fa[x])x=fa[x];
  52. return x;
  53. }
  54.  
  55. int delet(int x)
  56. {
  57. pushdown(x);
  58. int fx=fa[x];
  59. int ka=merge(ch[x][],ch[x][]);
  60. fa[ka]=fx;
  61. if( fx )ch[fx][x==ch[fx][]]=ka;
  62. while( fx ) {
  63. if( dis[ch[fx][]]<dis[ch[fx][]] )
  64. swap(ch[fx][],ch[fx][]);
  65. if( dis[fx]==dis[ch[fx][]]+ )
  66. return root;
  67. dis[fx]=dis[ch[fx][]]+;
  68. ka=fx;
  69. fx=fa[fx];
  70. }
  71. return ka;
  72. }
  73.  
  74. int add_point(int x,int v)
  75. {
  76. int fx=find(x);
  77. if( fx==x ) {
  78. if( ch[x][]+ch[x][]== ){
  79. val[x]+=v; return x;
  80. } else {
  81. if( ch[x][] ) fx=ch[x][];
  82. else fx=ch[x][];
  83. }
  84. }
  85. delet(x);
  86. val[x]+=v+sum(x);
  87. clear(x);
  88. return merge(find(fx),x);
  89. }
  90.  
  91. int build()
  92. {
  93. queue<int>t;
  94. for(int i=; i<=n; ++i) t.push(i);
  95. int x,y,z;
  96. while( t.size()> ) {
  97. x=t.front(); t.pop();
  98. y=t.front(); t.pop();
  99. z=merge(x,y);t.push(z);
  100. }
  101. return t.front();
  102. }
  103. }T,H;
  104.  
  105. void read(int &x)
  106. {
  107. x=; char ch=getchar(); bool flag=false;
  108. while( ch<'' || ch>'' ) {
  109. if( ch=='-' )flag=true;
  110. ch=getchar();
  111. }
  112. while( ch>='' && ch<='' ) {
  113. x=(x<<)+(x<<)+(ch^);
  114. ch=getchar();
  115. }
  116. flag?x*=(-):;
  117. }
  118.  
  119. int main()
  120. {
  121. read(n);
  122. T.dis[]=H.dis[]=-;
  123. for(int i=; i<=n; ++i){
  124. read(a[i]);
  125. T.val[i]=H.val[i]=a[i];
  126. }
  127. root=H.build();
  128. read(m);
  129. char op[];int x,y,fx,fy,temp;
  130. for(int i=; i<=m; ++i){
  131. scanf("%s",op);
  132. if( op[]=='A' ) {
  133. switch( op[] ){
  134. case '':
  135. read(x), read(y);
  136. root=H.delet(T.find(x));
  137. temp=T.add_point(x,y);
  138. H.val[temp]=T.val[temp];
  139. H.clear(temp);
  140. root=H.merge(root,temp);
  141. break;
  142.  
  143. case '':
  144. read(x), read(y); fx=T.find(x);
  145. root=H.delet(fx);
  146. T.val[fx]+=y; T.sign[fx]+=y;
  147. H.val[fx]=T.val[fx];
  148. H.clear(fx);
  149. root=H.merge(root,fx);
  150. break;
  151.  
  152. case '':
  153. read(y);
  154. allsign+=y;
  155. break;
  156. }
  157. } else if( op[]=='F' ) {
  158. switch( op[] ){
  159. case '':
  160. read(x);
  161. printf("%d\n",T.val[x]+allsign+T.sum(x));
  162. break;
  163.  
  164. case '':
  165. read(x);
  166. printf("%d\n",T.val[T.find(x)]+allsign);
  167. break;
  168.  
  169. case '':
  170. printf("%d\n",H.val[root]+allsign);
  171. break;
  172. }
  173. } else {
  174. read(x), read(y);
  175. fx=T.find(x), fy=T.find(y);
  176. if( fx==fy )continue;
  177. temp=T.merge(fx,fy);
  178. if( temp==fx )root=H.delet(fy);
  179. else root=H.delet(fx);
  180. }
  181. }
  182. return ;
  183. }

洛谷P3273 [SCOI2011] 棘手的操作 [左偏树]的更多相关文章

  1. 洛谷.3273.[SCOI2011]棘手的操作(左偏树)

    题目链接 还是80分,不是很懂. /* 七个操作(用左偏树)(t2表示第二棵子树): 1.合并:直接合并(需要将一个t2中原有的根节点删掉) 2.单点加:把这个点从它的堆里删了,加了再插入回去(有负数 ...

  2. bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作

    2333? 先记一下吧,这题现在全部都是照着题解做的,因为怎么改都改不出来,只好对着题解改,以后还要再做过 以后再也不用指针了!太恶心了!空指针可不止直接特判那么简单啊,竟然还要因为空指针写奇怪的分类 ...

  3. 洛谷P3273 [SCOI2011]棘手的操作

    题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点A1 x v: 将第x个节点的权 ...

  4. 洛谷P4331 [BOI2004] Sequence 数字序列 [左偏树]

    题目传送门 数字序列 题目描述 给定一个整数序列 a1​,a2​,⋅⋅⋅,an​ ,求出一个递增序列 b1​<b2​<⋅⋅⋅<bn​ ,使得序列 ai​ 和 bi​ 的各项之差的绝对 ...

  5. 模板 可并堆【洛谷P3377】 【模板】左偏树(可并堆)

    P3377 [模板]左偏树(可并堆) 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删 ...

  6. 洛谷P3066 [USACO12DEC] 逃跑的Barn [左偏树]

    题目传送门 逃跑的Barn 题目描述 It's milking time at Farmer John's farm, but the cows have all run away! Farmer J ...

  7. 洛谷$P4331\ [BOI2004]\ Sequence$ 数字序列 左偏树

    正解:左偏树 解题报告: 传送门$QwQ$ 开始看到的时候$jio$得长得很像之前做的一个$dp$,,, 但是$dp$那题是说不严格这里是严格? 不难想到我们可以让$a_{i},b_{i}$同时减去$ ...

  8. 洛谷P3261 [JLOI2015]城池攻占(左偏树)

    传送门 每一个城市代表的点开一个小根堆,把每一个骑士合并到它开始攻占的城池所代表的点上 然后开始dfs,每一次把子树里那些还活着的骑士合并上来 然后再考虑当前点的堆,一直pop直到骑士全死光或者剩下的 ...

  9. 2333: [SCOI2011]棘手的操作[离线线段树]

    2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Stat ...

随机推荐

  1. ZOJ 3778 C - Talented Chef 水题

    LINK:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3778 题意:有n道菜,每道菜需要\(a_i\)道工序,有m个锅可 ...

  2. Python学习笔记(四十一)— 内置模块(10)urllib

    摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432688314 ...

  3. spring boot 自定义属性覆盖application文件属性

    参考 Spring boot源码分析-ApplicationListener应用环境: https://blog.csdn.net/jamet/article/details/78042486 加载a ...

  4. qq上传文件进行测试要点分析

    功能 QQ 兼容性 1.Win系统/Mac系统  Android/IOS 品牌 传 1.上传方式:直接拖拽,按回车键上传 2.多个文件同时上传给一人/多人(考虑稳定性,是否存在内存泄露) 3.不是好友 ...

  5. makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解【转】

    转自:http://www.cnblogs.com/lifexy/p/7065175.html 在linux中输入vi Makefile 来实现创建Makefile文件 注意:命令行前必须加TAB键 ...

  6. Linux Kernel代码艺术——数组初始化【转】

    转自:http://www.cnblogs.com/hazir/p/array_initialization.html 前几天看内核中系统调用代码,在系统调用向量表初始化中,有下面这段代码写的让我有点 ...

  7. 2017 ACM ICPC Asia Regional - Daejeon

    2017 ACM ICPC Asia Regional - Daejeon Problem A Broadcast Stations 题目描述:给出一棵树,每一个点有一个辐射距离\(p_i\)(待确定 ...

  8. python脚本-实现自动按规则创建指定大小和指定个数的文件案例

    # -*- coding: cp936 -*-#---------------------------------------------------------------------------- ...

  9. [SVN技巧]代码提交中遇到的两个问题及其解决方案

    前言 SVN在使用的过程中会遇到各种各样的问题,小黑在最近的使用中,遇到如下的两个问题,这里贴出来供大家参考 问题记录 SVN在源码仓库中不存在,导致无法删除和上传 问题提示: Working cop ...

  10. 斐讯路由器L(联)B(壁)K-码兑换包安全下车通道(图文教程)

    大家好,最近大家比较关心的斐讯路由器如何下车问题,楼主亲自试提取了一遍,记录下过程,欢迎大家一起讨论. 言归正传,上图,上图! No.1 打开斐讯提供的良心k码退换通道: https://tech-s ...