[BZOJ4399]魔法少女LJJ
题目大意:
一个动态图,支持以下$7$种操作:
1.加入一个权值为$x$的点;
2.在点$a$和点$b$之间加入一条无向边;
3.在点$a$所属的连通块中将小于$x$的所有权值修改为$x$;
4.在点$a$所属的连通块中将大于$x$的所有权值修改为$x$;
5.查找点$a$所属的连通块中第$k$小的权值;
6.比较点$a$所属连通块中所有权值之积与点$b$所属连通块中所有权值之积的大小;
7.询问点$a$所属的连通块的大小。
思路:
建立一棵动态开点的权值线段树,支持以下$7$种操作:
1.插入一个点(新建一棵树);
2.合并两棵树(并查集);
3.询问$[1,x-1]$的元素个数,单点修改加到$x$上,并区间修改删除$[1,x-1]$的权值;
4.询问$[x+1,n]$的元素个数,单点修改加到$x$上,并区间修改删除$[x+1,n]$的权值;
5.查找全树第$k$最值;
6.对于线段树每个结点维护$\log$值,因为$\ln(a\times b)=\ln(a)+\ln(b)$,所以每次加起来比较和就行了;
7.返回整棵树的元素个数。
另外因为数据范围比较大需要离散化,要事先将整个文件读进来。
玄学问题:
1.区间修改打lazy tag似乎和暴力修改差不多,甚至会更慢;
2.似乎很容易被卡内存,因此同样的数据尽量只存一次,离散化宁可每次用std::lower_bound()。
低级错误:
1.$\log$维护老的权值,而不是离散化以后的新权值;
2.先进行线段树合并再并查集合并,不然并查集Find()的时候回返回同一个点;
3.离散化的时候vector是从$0$开始存的,因此最后通过离散的权值求原来的权值,应该是$w[b-1]$而不是$w[b]$;
4.单点修改的时候,原来的$val$值不一定是$1$。
优化:
1.在进行3、4操作时,如果查找到对应区间的元素个数是$0$,那么后面两个操作可以省掉;
2.在区间查询query(),区间修改删除clear()时,如果当前区间的元素个数是$0$,那么不需要再往下递归。
1 #include<cmath> 2 #include<cstdio> 3 #include<vector> 4 #include<bits/stl_algo.h> 5 #include<bits/localefwd.h> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int M=400001,logM=17; 14 int data[M][3]; 15 std::vector<int> w; 16 class DisjointSet { 17 private: 18 int anc[M]; 19 public: 20 DisjointSet() { 21 for(int i=0;i<M;i++) anc[i]=i; 22 } 23 int Find(const int x) { 24 return x==anc[x]?x:anc[x]=Find(anc[x]); 25 } 26 void Union(const int x,const int y) { 27 anc[Find(x)]=Find(y); 28 } 29 bool isConnected(const int x,const int y) { 30 return Find(x)==Find(y); 31 } 32 }; 33 DisjointSet s; 34 class SegmentTree { 35 private: 36 static const int nil=0; 37 static const int SIZE=M*logM; 38 int val[SIZE],left[SIZE],right[SIZE]; 39 double sum[SIZE]; 40 bool tag[SIZE]; 41 int sz; 42 int newnode() { 43 return ++sz; 44 } 45 void push_up(const int p) { 46 val[p]=val[left[p]]+val[right[p]]; 47 sum[p]=sum[left[p]]+sum[right[p]]; 48 } 49 void push_down(const int p) { 50 if(!tag[p]) return; 51 tag[p]=false; 52 tag[left[p]]=tag[right[p]]=true; 53 val[left[p]]=val[right[p]]=0; 54 sum[left[p]]=sum[right[p]]=0; 55 } 56 public: 57 int root[M]; 58 SegmentTree() { 59 sz=0; 60 val[nil]=0; 61 sum[nil]=0; 62 tag[nil]=false; 63 } 64 void insert(int &p,const int b,const int e,const int x) { 65 p=newnode(); 66 left[p]=right[p]=nil; 67 tag[p]=false; 68 if(b==e) { 69 val[p]=1; 70 sum[p]=log(w[x-1]); 71 return; 72 } 73 int mid=(b+e)>>1; 74 if(x<=mid) insert(left[p],b,mid,x); 75 if(x>mid) insert(right[p],mid+1,e,x); 76 push_up(p); 77 } 78 int merge(const int p1,const int p2) { 79 if(!p1||!p2) return p1|p2; 80 push_down(p1); 81 push_down(p2); 82 val[p1]+=val[p2]; 83 sum[p1]+=sum[p2]; 84 left[p1]=merge(left[p1],left[p2]); 85 right[p1]=merge(right[p1],right[p2]); 86 return p1; 87 } 88 void modify(int &p,const int b,const int e,const int x,const int y) { 89 if(!p) p=newnode(); 90 if(b==e) { 91 val[p]+=y; 92 sum[p]=log(w[b-1])*val[p]; 93 return; 94 } 95 push_down(p); 96 int mid=(b+e)>>1; 97 if(x<=mid) modify(left[p],b,mid,x,y); 98 if(x>mid) modify(right[p],mid+1,e,x,y); 99 push_up(p); 100 } 101 int query(const int p,const int b,const int e,const int l,const int r) { 102 if(!val[p]) return 0; 103 if((b==l)&&(e==r)) return val[p]; 104 push_down(p); 105 int mid=(b+e)>>1,ret=0; 106 if(l<=mid) ret+=query(left[p],b,mid,l,std::min(mid,r)); 107 if(r>mid) ret+=query(right[p],mid+1,e,std::max(mid+1,l),r); 108 return ret; 109 } 110 void clear(const int p,const int b,const int e,const int l,const int r) { 111 if(!val[p]) return; 112 if((b==l)&&(e==r)) { 113 val[p]=0; 114 sum[p]=0; 115 tag[p]=true; 116 } 117 push_down(p); 118 int mid=(b+e)>>1; 119 if(l<=mid) clear(left[p],b,mid,l,std::min(mid,r)); 120 if(r>mid) clear(right[p],mid+1,e,std::max(mid+1,l),r); 121 push_up(p); 122 } 123 void modify_less(int &p,const int b,const int e,const int x) { 124 int d=query(p,b,e,b,x-1); 125 if(!d) return; 126 modify(p,b,e,x,d); 127 clear(p,b,e,b,x-1); 128 } 129 void modify_greater(int &p,const int b,const int e,const int x) { 130 int d=query(p,b,e,x+1,e); 131 if(!d) return; 132 modify(p,b,e,x,d); 133 clear(p,b,e,x+1,e); 134 } 135 int find_kth(const int p,const int b,const int e,const int k) { 136 if(b==e) return w[b-1]; 137 push_down(p); 138 int mid=(b+e)>>1; 139 if(val[left[p]]>=k) return find_kth(left[p],b,mid,k); 140 return find_kth(right[p],mid+1,e,k-val[left[p]]); 141 } 142 bool cmp_product(const int x,const int y) { 143 return sum[x]>sum[y]; 144 } 145 int size(const int x) { 146 return val[x]; 147 } 148 }; 149 SegmentTree t; 150 int main() { 151 int m=getint(); 152 for(int i=0;i<m;i++) { 153 int &c=data[i][0]=getint(); 154 data[i][1]=getint(); 155 if(c!=1&&c!=7) data[i][2]=getint(); 156 if(c==1) w.push_back(data[i][1]); 157 if(c==3||c==4) w.push_back(data[i][2]); 158 } 159 std::sort(w.begin(),w.end()); 160 int n=std::unique(w.begin(),w.end())-w.begin(); 161 w.resize(n); 162 for(int i=0,cnt=0;i<m;i++) { 163 int &c=data[i][0]; 164 switch(c) { 165 case 1: { 166 cnt++; 167 int x=std::lower_bound(w.begin(),w.end(),data[i][1])-w.begin()+1; 168 t.insert(t.root[cnt],1,n,x); 169 break; 170 } 171 case 2: { 172 int &a=data[i][1],&b=data[i][2]; 173 if(s.isConnected(a,b)) continue; 174 t.root[s.Find(b)]=t.merge(t.root[s.Find(b)],t.root[s.Find(a)]); 175 s.Union(a,b); 176 break; 177 } 178 case 3: { 179 int &a=data[i][1],x=lower_bound(w.begin(),w.end(),data[i][2])-w.begin()+1; 180 t.modify_less(t.root[s.Find(a)],1,n,x); 181 break; 182 } 183 case 4: { 184 int &a=data[i][1],x=lower_bound(w.begin(),w.end(),data[i][2])-w.begin()+1; 185 t.modify_greater(t.root[s.Find(a)],1,n,x); 186 break; 187 } 188 case 5: { 189 int &a=data[i][1],&k=data[i][2]; 190 printf("%d\n",t.find_kth(t.root[s.Find(a)],1,n,k)); 191 break; 192 } 193 case 6: { 194 int &a=data[i][1],&b=data[i][2]; 195 printf("%d\n",t.cmp_product(t.root[s.Find(a)],t.root[s.Find(b)])); 196 break; 197 } 198 case 7: { 199 int &a=data[i][1]; 200 printf("%d\n",t.size(t.root[s.Find(a)])); 201 break; 202 } 203 } 204 } 205 return 0; 206 }
转载于:https://www.cnblogs.com/skylee03/p/7448212.html
[BZOJ4399]魔法少女LJJ相关推荐
- bzoj4399 魔法少女LJJ
这题不愧为4399. 4399: 魔法少女LJJ Time Limit: 20 Sec Memory Limit: 162 MB Submit: 622 Solved: 145 [Submit][ ...
- BZOJ4399魔法少女LJJ——线段树合并+并查集
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉 ...
- BZOJ4399 魔法少女LJJ【线段树合并】【并查集】
Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅 ...
- [BZOJ4399]魔法少女LJJ(线段树合并)
请仔细阅读数据范围,c<=7. 线段树合并裸题,对于乘积大小比较,使用log即可. 1 #include<cmath> 2 #include<cstdio> 3 #inc ...
- bzoj4399 魔法少女LJJ 线段树合并
只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...
- 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉 ...
- BZOJ 4399: 魔法少女LJJ
4399: 魔法少女LJJ Time Limit: 20 Sec Memory Limit: 162 MB Submit: 287 Solved: 73 Description 在森林中见过会动的树, ...
- bzoj 4399 魔法少女LJJ
4399: 魔法少女LJJ Time Limit: 20 Sec Memory Limit: 162 MB http://www.lydsy.com/JudgeOnline/problem.php? ...
- 魔法少女 LJJ——线段树
题目 [题目描述] 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女 LJJ 已经觉得自己见过世界上的所有稀奇古怪的事情了. LJJ 感叹道"这里真是个迷人的绿色世界,空气清新. ...
最新文章
- Android 中文 API 文档 (45) —— AbsoluteLayout.LayoutParams
- 生成删除约束语句 SQL语句
- printf 指针地址_c语言入门 第十四章指针
- Javascript 笔记与总结(1-4)this
- google us web
- 并发、并行、线程、进程与CPU基本概念
- 网络分析仪-inSSIDer
- c语言编写弹窗提示是否确认退出_弹窗设计的5条基本原则
- return view前端怎么获取_Web 前端路由原理解析和功能实现
- 前端面试要注意这几点
- 漏洞战争: 软件漏洞发展趋势
- OpenStack DVR 原理深入分析
- 【数据仓库与OLAP技术】期末复习+考题
- Java中文件File相关知识
- 计算机自动关机启机唤醒设置,电脑在哪设置定时关机(如何设置电脑的自动关机和自动开机)...
- WhereDidMyTimeGo - 一款帮你记录每天的时间分配的MacOS app
- pushplus通过企业微信应用给微信发送消息教程
- cpu怎么开启php,cpu怎么换
- java编写水数仙花,【360高手联盟-小仙】【JAVASE编程基础】02-JAVA程序的基本结构和基础语法...
- 基于NIO的Client/Server程序实践
热门文章
- 零基础Java学习之final关键字
- 2018年这些UI设计趋势正在流行,跟上必拿高薪!
- stopImmediatePropagation函数和stopPropagation函数的区别
- 【leetcode】Balanced Binary Tree(middle)
- ASP.NET那点不为人知的事(四)
- 用SAXBuilder、Document、Element操作xml
- GridView 里的删除不起作用
- OpenCv 金字塔之上采样与下采样
- springboot中下面哪一个作为jpa默认实现_天天在用SpringBoot,手撸一个的Starter试试!...
- python 驱动级鼠标_Python介绍、安装