题目链接

还是80分,不是很懂。

  1. /*
  2. 七个操作(用左偏树)(t2表示第二棵子树):
  3. 1.合并:直接合并(需要将一个t2中原有的根节点删掉)
  4. 2.单点加:把这个点从它的堆里删了,加了再插入回去(有负数)(它可能成为这一个堆的根,所以也要从t2中删除再插入)
  5. 3.整个连通块加:根节点打标记(从t2中删除,改数,再插入到t2)
  6. 4.所有节点加:全局标记
  7. 5.输出某个点的值:向上加上所有父节点的值,输出
  8. 6.输出某个点所在连通块的最大值:找到根,输出
  9. 7.输出所有节点的最大值:将所有堆的根节点取出,再维护第二棵子树
  10. (1)
  11. 在要改动子节点要下传父节点标记,像线段树一样
  12. (2)
  13. 左偏树的删除:左偏树不具有平衡树的性质,所以做不到删除权值为某个值的点,但是可以删除指定下标的点
  14. 先合并要删除的点x的左右子树为s,再将左右合并后的子树与fa[x]合并
  15. 合并后新树距离可能会改变,因此要更新fa[x]的距离
  16. 如果dis[s]+1<dis[fa],则dis[fa]的距离要改小,如果s是fa的左子树,还要交换左右子树
  17. 因为dis[fa]的距离改了所以要继续往上
  18. 如果dis[s]+1>dis[fa],如果s是左子树就可以结束;如果是右子树,若dis[s]<dis[left],则更新fa的距离,否则还要再交换一次子树,再向上更新
  19. (3)
  20. 单点加/减(主要是减)有可能在根,这会导致树根发生改变
  21. 对于第二棵左偏树,需要维护树根位置以解决操作7
  22. (4)
  23. 注意第二棵树开始时的建树,将所有原节点合并
  24. (5)
  25. 合并两棵子树需将那棵根不是合并后的根节点的子树从第二棵中删掉
  26. (6)
  27. 第二棵树存的是每堆的根节点,所以要对对应堆的根节点进行操作
  28. (7)
  29. 将一个点取出重新插入时记得Init
  30. */
  31. #include<cstdio>
  32. #include<cctype>
  33. #include<algorithm>
  34. //#define gc() (SS==TT &&(TT=(SS=IN)+fread(IN,1,1<<22,stdin),SS==TT)?EOF:*SS++)
  35. #define gc() getchar()
  36. const int N=3e5+5;
  37. int n,TAG,q[N],root;
  38. //char IN[1<<22],*SS=IN,*TT=IN;
  39. inline int read()
  40. {
  41. int now=0,f=1;register char c=gc();
  42. for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
  43. for(;isdigit(c);now=now*10+c-'0',c=gc());
  44. return now*f;
  45. }
  46. struct Leftist_Tree
  47. {
  48. int val[N],fa[N],son[N][2],tag[N],dis[N];
  49. void Init(int p){fa[p]=son[p][0]=son[p][1]=0;}
  50. inline void PushDown(int x)
  51. {
  52. if(son[x][0]) val[son[x][0]]+=tag[x],tag[son[x][0]]+=tag[x];
  53. if(son[x][1]) val[son[x][1]]+=tag[x],tag[son[x][1]]+=tag[x];
  54. tag[x]=0;
  55. }
  56. int Getf(int p)
  57. {
  58. while(fa[p]) p=fa[p];
  59. return p;
  60. }
  61. int Sum(int p)//到根节点路径的标记和
  62. {
  63. int res=0;
  64. while(p=fa[p]) res+=tag[p];
  65. return res;
  66. }
  67. int Merge(int A,int B)
  68. {
  69. if(!A||!B) return A+B;
  70. if(val[A]<val[B]) std::swap(A,B);
  71. if(tag[A]) PushDown(A);
  72. son[A][1]=Merge(son[A][1],B);
  73. fa[son[A][1]]=A;
  74. if(dis[son[A][1]]>dis[son[A][0]]) std::swap(son[A][0],son[A][1]);
  75. dis[A]=dis[son[A][1]]+1;
  76. return A;
  77. }
  78. int Delete(int x)
  79. {
  80. if(tag[x]) PushDown(x);
  81. int f=fa[x],s=Merge(son[x][0],son[x][1]);
  82. fa[s]=f;
  83. if(f) son[f][son[f][1]==x]=s;
  84. while(f)
  85. {
  86. if(dis[son[f][0]]<dis[son[f][1]]) std::swap(son[f][0],son[f][1]);
  87. if(dis[son[f][1]]+1==dis[f]) return root;//根节点没有改变(距离并未发生改变),直接return原来的根
  88. dis[f]=dis[son[f][1]]+1;
  89. // fa[son[f][1]]=f;
  90. s=f, f=fa[f];
  91. }
  92. return s;//新的根节点 这个不要随便设,初始就是s,因为s可能就是根节点(f=0)
  93. }
  94. int Add_Point(int x,int v)
  95. {
  96. int rt=Getf(x);
  97. if(rt==x)
  98. if(!(son[x][0]+son[x][1])||v>=0){val[x]+=v;return x;}
  99. else if(son[x][0]) rt=son[x][0];
  100. else rt=son[x][1];
  101. Delete(x);
  102. val[x]+=v+Sum(x);
  103. Init(x);
  104. return Merge(Getf(rt),x);//要合并Getf(rt)!删除后已经更新树了
  105. }
  106. int Build()
  107. {
  108. int h=0,t=0,x,y;
  109. for(int i=1;i<=n;++i) q[t++]=i;
  110. while(h<t-1)
  111. {
  112. x=q[h++],y=q[h++];
  113. q[t++]=Merge(x,y);
  114. }
  115. return q[t-1];//返回第二棵子树的根节点
  116. }
  117. }t1,t2;
  118. int main()
  119. {
  120. #ifndef ONLINE_JUDGE
  121. freopen("3273.in","r",stdin);
  122. #endif
  123. t1.dis[0]=t2.dis[0]=-1;
  124. n=read();
  125. for(int i=1;i<=n;++i) t1.val[i]=t2.val[i]=read();
  126. root=t2.Build();
  127. int q=read(),x,y,rx,ry,v,tmp;
  128. char s[5];
  129. while(q--)
  130. {
  131. scanf("%s",s);
  132. if(s[0]=='U')
  133. {
  134. x=read(),y=read(),rx=t1.Getf(x),ry=t1.Getf(y);
  135. if(rx==ry) continue;
  136. tmp=t1.Merge(rx,ry);
  137. if(tmp==rx) root=t2.Delete(ry);
  138. else root=t2.Delete(rx);
  139. }
  140. else if(s[0]=='A')
  141. if(s[1]=='1')
  142. {
  143. x=read(),v=read();
  144. root=t2.Delete(t1.Getf(x));
  145. ry=t1.Add_Point(x,v);//第一棵子树更新后x所在堆的根节点
  146. t2.val[ry]=t1.val[ry];
  147. t2.Init(ry);
  148. root=t2.Merge(root,ry);
  149. }
  150. else if(s[1]=='2')
  151. {
  152. x=read(),v=read();
  153. root=t2.Delete((rx=t1.Getf(x)));
  154. t1.val[rx]+=v, t1.tag[rx]+=v;
  155. t2.val[rx]=t1.val[rx];
  156. t2.Init(rx);
  157. root=t2.Merge(root,rx);
  158. }
  159. else
  160. v=read(), TAG+=v;
  161. else if(s[0]=='F')
  162. if(s[1]=='1') x=read(), printf("%d\n",t1.val[x]+t1.Sum(x)+TAG);
  163. else if(s[1]=='2') x=read(), printf("%d\n",t1.val[t1.Getf(x)]+TAG);
  164. else printf("%d\n",t2.val[root]+TAG);
  165. }
  166. return 0;
  167. }

洛谷.3273.[SCOI2011]棘手的操作(左偏树)的更多相关文章

  1. 洛谷P3273 [SCOI2011] 棘手的操作 [左偏树]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Django配置图片上传

    本文首先实现django中上传图片的过程,然后解决富文本编辑器文件上传的问题. 一. 上传图片 1.在 settings.py 中配置MEDIA_URL  和 MEDIA_ROOT 在 D:\blog ...

  2. WDS 三种模式

    (1)懒人模式(Lazy mode) 此模式下不需要填写对端的BSSID,本端AP的WDS连接作为被动连接,只需要对端填写了本端AP的BSSID即可,效果和桥接模式一样. (2)桥接模式(Bridge ...

  3. zabbix添加对自定义无规则的关键日志文件的监控

    zabbix添加对自定义无规则日志文件的监控 项目背景及思路: zabbix自带有针对日志文件的监控,自带的监控只能监控到指定文件或者正则匹配的固定日志文件,但当需要监控的文件名没有规律的时候自带监控 ...

  4. 转载:详解Java 自动装箱与拆箱的实现原理

    原文:http://www.jb51.net/article/111847.htm 什么是自动装箱和拆箱 自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对 ...

  5. 单例模式(懒汉、饿汉、同步锁、static、枚举)实现

    使用前提: 需要频繁的进行创建和销毁的对象,创建对象时耗时过多或耗费资源过多 三要素: 1.构造方法私有化: 2.实例化的变量引用私有化: 3.获取实例的方法共有. 1.饿汉式单例 弊端:在类装载的时 ...

  6. webpack 3之hash、chunkhash和contenthash三者的区别

    在使用webpack 3中,文件名的hash值可以有三种hash生成方式,那具体使用哪一种呢? 1.hash 如果都使用hash的话,所有文件的hash都是一样的,而且每次修改任何一个文件,所有文件名 ...

  7. js判断用户的浏览器

    1,判断pc和移动端 function browserRedirect() { var sUserAgent = navigator.userAgent.toLowerCase(); var bIsI ...

  8. C++ code:main参数

    main函数的参数结构为两项参数: int main(int argc,char** argv){……} main的参数由操作系统传递,所以比较特殊.两个形参名一般是采用习惯名称argc和argv,表 ...

  9. ural1855 线段树区间更新+推公式维护一元二次式

    和威威猫系列故事差不多,都是根据条件推出公式 /* 操作c a b d:a到b道路上的所有边权值加d 操作e a b:问a到b中包含的道路的平均权值 区间平均值=所有可能路径权值/所有路径数, 而路径 ...

  10. python 全栈开发,Day35(TCP协议 粘包现象 和解决方案)

    一.TCP协议 粘包现象 和解决方案 黏包现象让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)执行远程命令的模块 需要用到模块subprocess sub ...