感谢线段树进阶,给了我重新做人的机会。---------------某不知名OIer,Keen_z

Description

题目描述

在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道“这里真是个迷人的绿色世界,空气清新、淡雅,到处散发着醉人的奶浆味;小猴在枝头悠来荡去,好不自在;各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果;鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境” SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树,动态仙人掌了,那么今天就来见识一下动态图吧” LJJ:“要支持什么操作?” SHY:“ 1.新建一个节点,权值为x。 2.连接两个节点。 3.将一个节点a所属于的联通快内权值小于x的所有节点权值变成x。 4.将一个节点a所属于的联通快内权值大于x的所有节点权值变成x。 5.询问一个节点a所属于的联通块内的第k小的权值是多少。 6.询问一个节点a所属联通快内所有节点权值之积与另一个节点b所属联通快内所有节点权值之积的大小。 7.询问a所在联通快内节点的数量 8.若两个节点a,b直接相连,将这条边断开。 9.若节点a存在,将这个点删去。 ” LJJ:“我可以离线吗?” SHY:“可以,每次操作是不加密的,” LJJ:“我可以暴力吗?” SHY:“自重” LJJ很郁闷,你能帮帮他吗

输入格式

第一行有一个正整数m,表示操作个数。 接下来m行,每行先给出1个正整数c。 若c=1,之后一个正整数x,表示新建一个权值为x的节点,并且节点编号为n+1(当前有n个节点)。 若c=2,之后两个正整数a,b,表示在a,b之间连接一条边。 若c=3,之后两个正整数a,x,表示a联通快内原本权值小于x的节点全部变成x。 若c=4,之后两个正整数a,x,表示a联通快内原本权值大于x的节点全部变成x。 若c=5,之后两个正整数a,k,表示询问a所属于的联通块内的第k小的权值是多少。 若c=6,之后两个正整数a,b,表示询问a所属联通快内所有节点权值之积与b所属联通快内所有节点权值之积的大小, 若a所属联通快内所有节点权值之积大于b所属联通快内所有节点权值之积,输出1,否则为0。 若c=7,之后一个正整数a,表示询问a所在联通块大小 若c=8,之后两个正整数a,b,表示断开a,b所连接的边。 若c=9,之后一个正整数a,表示断开a点的所有连边 具体输出格式见样例

HINT

对100%的数据 0<=m<=400000,c<=7,所有出现的数均<=1000000000,所有出现的点保证存在 【HINT】请认真阅读题面

Solution

给了8,9两个阴间删点删边操作之后告诉你c<=7。。

一个很喵的转化,可以将连乘转化为对数之和。

数据最大1e9,显然不能直接开线段树,需要离散化。

将每个联通块都看作一个线段树,在其中维护权值为i的点的个数与元素对数的和。连边时将两点所在的线段树合并。

过程中要用一波并察集操作,来及时更新合并后线段树的根。

主要还是看代码吧,应该挺好理解的(挺不好调的

附去掉9 1后的样例输入,输出应为5。


code:

  1. #include<bits/stdc++.h>
  2. #define debug cout<<"wrong"<<endl
  3. using namespace std;
  4. const int NN=4e5+5;
  5. int hal,id,c[NN],rt[NN],m,dat[NN][3],has[NN],cnt,fa[NN],s;
  6. double logg[NN];
  7. inline signed read(){
  8. int x=0,f=1;
  9. char ch=getchar();
  10. while(ch<'0'||ch>'9')
  11. {
  12. if(ch=='-') f=-1;
  13. ch=getchar();
  14. }
  15. while(ch<='9'&&ch>='0')
  16. {
  17. x=(x<<1)+(x<<3)+(ch^48);
  18. ch=getchar();
  19. }
  20. return x*f;
  21. }
  22. void write(int x){
  23. if(x<0) putchar('-'), x=-x;
  24. if(x>9) write(x/10);
  25. putchar(x%10+'0');
  26. }
  27. int get(int x){
  28. return fa[x]==x?x:fa[x]=get(fa[x]);
  29. }
  30. inline int cag(int x){
  31. return lower_bound(has+1,has+1+hal,x)-has;
  32. }
  33. struct node{
  34. int seg,ls[NN*20],rs[NN*20],caf[NN*20],siz[NN*20];
  35. double sum[NN*20];
  36. void pushup(int x){
  37. sum[x]=sum[ls[x]]+sum[rs[x]];
  38. siz[x]=siz[ls[x]]+siz[rs[x]];
  39. }
  40. void insert(int &x,int l,int r,int pos,int w){
  41. if(!x) x=++seg;
  42. if(l==r){
  43. sum[x]+=logg[pos]*w;
  44. siz[x]+=w;
  45. return;
  46. }
  47. int mid=(l+r)>>1;
  48. if(pos<=mid) insert(ls[x],l,mid,pos,w);
  49. else insert(rs[x],mid+1,r,pos,w);
  50. pushup(x);
  51. }
  52. int query(int x,int l,int r,int pos){
  53. if(l==r) return l;
  54. int mid=(l+r)>>1;
  55. if(siz[ls[x]]>=pos) return query(ls[x],l,mid,pos);
  56. else return query(rs[x],mid+1,r,pos-siz[ls[x]]);
  57. }
  58. void marge(int &x,int y,int l,int r){
  59. if(!x||!y){
  60. x=x+y;
  61. return;
  62. }
  63. if(l==r){
  64. siz[x]+=siz[y];
  65. sum[x]+=sum[y];
  66. return;
  67. }
  68. int mid=(l+r)>>1;
  69. marge(ls[x],ls[y],l,mid);
  70. marge(rs[x],rs[y],mid+1,r);
  71. pushup(x);
  72. }
  73. void delet(int x,int l,int r,int opl,int opr){
  74. if(!siz[x]) return;
  75. if(l==r){
  76. s+=siz[x];
  77. sum[x]=siz[x]=0;
  78. return;
  79. }
  80. int mid=(l+r)>>1;
  81. if(opl<=mid) delet(ls[x],l,mid,opl,opr);
  82. if(opr>mid) delet(rs[x],mid+1,r,opl,opr);
  83. pushup(x);
  84. }
  85. }segt;
  86. int main(){
  87. m=read();
  88. for(int i=1;i<=m;i++){
  89. c[i]=read(); dat[i][1]=read();
  90. if(c[i]!=1&&c[i]!=7) dat[i][2]=read();
  91. if(c[i]==1) has[++cnt]=dat[i][1], dat[i][2]=++id;
  92. if(c[i]==3||c[i]==4) has[++cnt]=dat[i][2];
  93. }
  94. sort(has+1,has+cnt+1);
  95. hal=unique(has+1,has+cnt+1)-(has+1);
  96. for(int i=1;i<=m;i++)
  97. switch(c[i]){
  98. case 1:{
  99. int x=cag(dat[i][1]);
  100. logg[x]=log(dat[i][1]);
  101. segt.insert(rt[dat[i][2]],1,hal,x,1);
  102. fa[dat[i][2]]=dat[i][2];
  103. break;
  104. }
  105. case 2:{
  106. int rx=get(dat[i][1]),ry=get(dat[i][2]);
  107. if(rx!=ry){
  108. fa[ry]=rx;
  109. segt.marge(rt[rx],rt[ry],1,hal);
  110. }
  111. break;
  112. }
  113. case 3:{
  114. int x=cag(dat[i][2]),ro=get(dat[i][1]);
  115. s=0; logg[x]=log(dat[i][2]);
  116. segt.delet(rt[ro],1,hal,1,max(1,x-1));
  117. if(s) segt.insert(rt[ro],1,hal,x,s);
  118. break;
  119. }
  120. case 4:{
  121. int x=cag(dat[i][2]),ro=get(dat[i][1]);
  122. s=0; logg[x]=log(dat[i][2]);
  123. segt.delet(rt[ro],1,hal,min(hal,x+1),hal);
  124. if(s) segt.insert(rt[ro],1,hal,x,s);
  125. break;
  126. }
  127. case 5:{
  128. int ro=get(dat[i][1]);
  129. int ans=segt.query(rt[ro],1,hal,dat[i][2]);
  130. write(has[ans]); putchar('\n');
  131. break;
  132. }
  133. case 6:{
  134. int r1=get(dat[i][1]),r2=get(dat[i][2]);
  135. if(segt.sum[rt[r1]]>segt.sum[rt[r2]]) puts("1");
  136. else puts("0");
  137. break;
  138. }
  139. case 7:{
  140. int ro=get(dat[i][1]);
  141. write(segt.siz[rt[ro]]); putchar('\n');
  142. break;
  143. }
  144. }
  145. }
  146. /*
  147. 11
  148. 1 2
  149. 1 3
  150. 1 4
  151. 1 5
  152. 1 6
  153. 2 1 2
  154. 2 2 3
  155. 2 3 4
  156. 2 4 5
  157. 3 2 5
  158. 5 3 4
  159. */

Code

  1. 1 #include<bits/stdc++.h>
  2. 2 #define debug cout<<"lbwnb"<<endl
  3. 3 using namespace std;
  4. 4 const int NN=4e5+5;
  5. 5 int hal,id,c[NN],rt[NN],m,dat[NN][3],has[NN],cnt,fa[NN],s;
  6. 6 double logg[NN];
  7. 7 inline signed read(){
  8. 8 int x=0,f=1;
  9. 9 char ch=getchar();
  10. 10 while(ch<'0'||ch>'9')
  11. 11 {
  12. 12 if(ch=='-') f=-1;
  13. 13 ch=getchar();
  14. 14 }
  15. 15 while(ch<='9'&&ch>='0')
  16. 16 {
  17. 17 x=(x<<1)+(x<<3)+(ch^48);
  18. 18 ch=getchar();
  19. 19 }
  20. 20 return x*f;
  21. 21 }
  22. 22 void write(int x){
  23. 23 if(x<0) putchar('-'), x=-x;
  24. 24 if(x>9) write(x/10);
  25. 25 putchar(x%10+'0');
  26. 26 }
  27. 27 int get(int x){
  28. 28 return fa[x]==x?x:fa[x]=get(fa[x]);
  29. 29 }
  30. 30 inline int cag(int x){
  31. 31 return lower_bound(has+1,has+1+hal,x)-has;
  32. 32 }
  33. 33 struct node{
  34. 34 int seg,ls[NN*20],rs[NN*20],caf[NN*20],siz[NN*20];
  35. 35 double sum[NN*20];
  36. 36 void pushup(int x){
  37. 37 sum[x]=sum[ls[x]]+sum[rs[x]];
  38. 38 siz[x]=siz[ls[x]]+siz[rs[x]];
  39. 39 }
  40. 40 void insert(int &x,int l,int r,int pos,int w){
  41. 41 if(!x) x=++seg;
  42. 42 if(l==r){
  43. 43 sum[x]+=logg[pos]*w;
  44. 44 siz[x]+=w;
  45. 45 return;
  46. 46 }
  47. 47 int mid=(l+r)>>1;
  48. 48 if(pos<=mid) insert(ls[x],l,mid,pos,w);
  49. 49 else insert(rs[x],mid+1,r,pos,w);
  50. 50 pushup(x);
  51. 51 }
  52. 52 int query(int x,int l,int r,int pos){
  53. 53 if(l==r) return l;
  54. 54 int mid=(l+r)>>1;
  55. 55 if(siz[ls[x]]>=pos) return query(ls[x],l,mid,pos);
  56. 56 else return query(rs[x],mid+1,r,pos-siz[ls[x]]);
  57. 57 }
  58. 58 void marge(int &x,int y,int l,int r){
  59. 59 if(!x||!y){
  60. 60 x=x+y;
  61. 61 return;
  62. 62 }
  63. 63 if(l==r){
  64. 64 siz[x]+=siz[y];
  65. 65 sum[x]+=sum[y];
  66. 66 return;
  67. 67 }
  68. 68 int mid=(l+r)>>1;
  69. 69 marge(ls[x],ls[y],l,mid);
  70. 70 marge(rs[x],rs[y],mid+1,r);
  71. 71 pushup(x);
  72. 72 }
  73. 73 void delet(int x,int l,int r,int opl,int opr){
  74. 74 if(!siz[x]) return;
  75. 75 if(l==r){
  76. 76 s+=siz[x];
  77. 77 sum[x]=siz[x]=0;
  78. 78 return;
  79. 79 }
  80. 80 int mid=(l+r)>>1;
  81. 81 if(opl<=mid) delet(ls[x],l,mid,opl,opr);
  82. 82 if(opr>mid) delet(rs[x],mid+1,r,opl,opr);
  83. 83 pushup(x);
  84. 84 }
  85. 85 }segt;
  86. 86 int main(){
  87. 87 m=read();
  88. 88 for(int i=1;i<=m;i++){
  89. 89 c[i]=read(); dat[i][1]=read();
  90. 90 if(c[i]!=1&&c[i]!=7) dat[i][2]=read();
  91. 91 if(c[i]==1) has[++cnt]=dat[i][1], dat[i][2]=++id;
  92. 92 if(c[i]==3||c[i]==4) has[++cnt]=dat[i][2];
  93. 93 }
  94. 94 sort(has+1,has+cnt+1);
  95. 95 hal=unique(has+1,has+cnt+1)-(has+1);
  96. 96 for(int i=1;i<=m;i++)
  97. 97 switch(c[i]){
  98. 98 case 1:{
  99. 99 int x=cag(dat[i][1]);
  100. 100 logg[x]=log(dat[i][1]);
  101. 101 segt.insert(rt[dat[i][2]],1,hal,x,1);
  102. 102 fa[dat[i][2]]=dat[i][2];
  103. 103 break;
  104. 104 }
  105. 105 case 2:{
  106. 106 int rx=get(dat[i][1]),ry=get(dat[i][2]);
  107. 107 if(rx!=ry){
  108. 108 fa[ry]=rx;
  109. 109 segt.marge(rt[rx],rt[ry],1,hal);
  110. 110 }
  111. 111 break;
  112. 112 }
  113. 113 case 3:{
  114. 114 int x=cag(dat[i][2]),ro=get(dat[i][1]);
  115. 115 s=0; logg[x]=log(dat[i][2]);
  116. 116 segt.delet(rt[ro],1,hal,1,max(1,x-1));
  117. 117 if(s) segt.insert(rt[ro],1,hal,x,s);
  118. 118 break;
  119. 119 }
  120. 120 case 4:{
  121. 121 int x=cag(dat[i][2]),ro=get(dat[i][1]);
  122. 122 s=0; logg[x]=log(dat[i][2]);
  123. 123 segt.delet(rt[ro],1,hal,min(hal,x+1),hal);
  124. 124 if(s) segt.insert(rt[ro],1,hal,x,s);
  125. 125 break;
  126. 126 }
  127. 127 case 5:{
  128. 128 int ro=get(dat[i][1]);
  129. 129 int ans=segt.query(rt[ro],1,hal,dat[i][2]);
  130. 130 write(has[ans]); putchar('\n');
  131. 131 break;
  132. 132 }
  133. 133 case 6:{
  134. 134 int r1=get(dat[i][1]),r2=get(dat[i][2]);
  135. 135 if(segt.sum[rt[r1]]>segt.sum[rt[r2]]) puts("1");
  136. 136 else puts("0");
  137. 137 break;
  138. 138 }
  139. 139 case 7:{
  140. 140 int ro=get(dat[i][1]);
  141. 141 write(segt.siz[rt[ro]]); putchar('\n');
  142. 142 break;
  143. 143 }
  144. 144 }
  145. 145 }
  146. 146 /*
  147. 147 11
  148. 148 1 2
  149. 149 1 3
  150. 150 1 4
  151. 151 1 5
  152. 152 1 6
  153. 153 2 1 2
  154. 154 2 2 3
  155. 155 2 3 4
  156. 156 2 4 5
  157. 157 3 2 5
  158. 158 5 3 4

[BZOJ4399]魔法少女LJJ----------线段树进阶的更多相关文章

  1. BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...

  2. bzoj4399 魔法少女LJJ 线段树合并

    只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...

  3. bzoj4399 魔法少女LJJ 线段树合并+线段树二分+并查集

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4399 题解 毒瘤题 \(9\) 种操作还有支持动态图的连通性 仔细读题 $ c<=7$. ...

  4. 【BZOJ4399】魔法少女LJJ 线段树合并

    [BZOJ4399]魔法少女LJJ Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的 ...

  5. 魔法少女 LJJ——线段树

    题目 [题目描述] 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女 LJJ 已经觉得自己见过世界上的所有稀奇古怪的事情了. LJJ 感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处 ...

  6. BZOJ 4399: 魔法少女LJJ 线段树合并 + 对数

    Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着 ...

  7. BZOJ.4399.魔法少女LJJ(线段树合并)

    BZOJ 注意\(c\leq7\)→_→ 然后就是裸的权值线段树+线段树合并了. 对于取\(\max/\min\)操作可以直接区间修改清空超出范围的值,然后更新到对应位置上就行了(比如对\(v\)取\ ...

  8. BZOJ 4399: 魔法少女LJJ(线段树)

    传送门 解题思路 出题人真会玩..操作\(2\)线段树合并,然后每棵线段树维护元素个数和.对于\(6\)这个询问,因为乘积太大,所以要用对数.时间复杂度\(O(nlogn)\) 代码 #include ...

  9. BZOJ4399 魔法少女LJJ【线段树合并】【并查集】

    Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅 ...

随机推荐

  1. VUE001. 拖动div盒子(自定义指令v-directives)

    拖动div是一个逻辑很简单的需求,监听容器的鼠标按下松开的事件,执行函数通过DOM改变标签的CSS偏移量. 在VUE构建的项目中,通过标签的 @mousedown 和 @mouseup 赋予行为事件, ...

  2. jsp&mvc开发模式&jstl标签&三层架构

    目录 jsp 概念 原理 jsp 的脚本 jsp的内置对象 指令 注释 mvc:开发模式 jsp演变历史 mvc 优缺点 El表达式 JSTL 标签 练习 三层架构:软件设计架构 案例:用户信息列表展 ...

  3. Expression 表达式动态生成

    http://blog.csdn.net/duan1311/article/details/51769119 以上是拼装和调用GroupBy的方法,是不是很简单,只要传入分组列与合计列就OK了! 下面 ...

  4. Ubuntu中类似QQ截图的截图工具并实现鼠标右键菜单截图

    @ 目录 简介: 安装: 设置快捷键: 实现鼠标右键菜单截图: 简介: 在Windows中用惯了强大易用的QQ截图,会不习惯Ubuntu中的截图工具. 软件名为火焰截图,功能类似QQ截图,可以设置快捷 ...

  5. Azure 实践(4)- CI/CD .netcore项目Docker构建及部署

    上篇已介绍了.netcore项目构建的相关步骤,本篇继续完善 1.什么是CI/CD CI/CD 中的"CI"始终指持续集成,它属于开发人员的自动化流程.成功的 CI 意味着应用代码 ...

  6. Linux内核中断顶半部和底半部的理解

    文章目录 中断上半部.下半部的概念 实现中断下半部的三种方法 软中断 软中断模版 tasklet tasklet函数模版 工作队列 工作队列函数模版 进程上下文和中断上下文 软中断和硬中断的区别 硬中 ...

  7. dedecms织梦调用指定文章id

    {dede:arclist idlist="1349"  channelid="1" addfields="date,city"} idli ...

  8. js 模板方法模式

    * 分离出共同点 function Beverage() {} Beverage.prototype.boilWater = function() { console.log("把水煮沸&q ...

  9. java 小算法

    //鸡兔同笼 20个头 58腿 for(int a=0;a<=20;a++) { int b = 20-a; if((2*b+4*a)==58) { System.out.println(a+& ...

  10. List接口常用实现类对比

    相同点 都实现了List接口 储存了有序 可重复的数据 不同点 ArrayList 线程不安全 但是效率高 底层使用 Object[] elementData 实现 LinkedList 底层使用双向 ...