[luogu5344]逛森林
由于没有删边操作,可以先建出整棵森林,之后再用并查集判断是否连通,若连通必然与最后的森林相同
但如果用树链剖分+线段树的形式来优化建图,更具体如下:
建立两颗线段树,左边从儿子连向父亲,右边从父亲连向儿子,再将右边线段树上的连向左边对应的点,那么复杂度为$o(m\log^{3}n)$(前两个$\log$为边数,最后一个$\log$是求最短路)
考虑倍增去建立,由于可以重复建立,用ST表的方法去做即可,这样每一条链只对应于至多4个点(上下各两个),即边数为$o(m)$
还有一个问题,就是如何建立倍增所新增的点之间的边,这个并没有线段树的结构那么简单,如果暴力来说,即对于每一个点,向所有包含其的倍增的链连边,这样的边数是$o(n^{2})$的
下面考虑这样一种方式:对于每一个长度不小于2的倍增的链(即不为一个点),向组成其的两条链连边即可,不难发现此时对于一个点以及包含其的倍增的链,这条链的两部分中总(恰好)有一个部分包含该点,由此归纳即可证明这样的连边与前面暴力等价,这一部分的边数降为$o(n\log n)$
总复杂度为$o(m\log n+n\log^{2}n)$,可以通过
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 50005
4 #define M 1000005
5 #define oo 0x3f3f3f3f
6 #define pii pair<int,int>
7 #define mp make_pair
8 struct Edge{
9 int nex,to,len;
10 }edge[(N<<6)+(M<<4)];
11 struct op{
12 int p,x1,y1,x2,y2,w;
13 }a[M];
14 vector<int>vl,vr,v[N];
15 priority_queue<pii >q;
16 int V,E,n,m,s,fa[N],dep[N],f[N][16],head[N<<5],vis[N<<5],d[N<<5];
17 int find(int k){
18 if (k==fa[k])return k;
19 return fa[k]=find(fa[k]);
20 }
21 bool check(int x,int y){//1表示不相连
22 return find(x)!=find(y);
23 }
24 void merge(int x,int y){
25 fa[find(x)]=find(y);
26 }
27 int id(int k,int x){
28 return (k-1)*16+x+1;
29 }
30 int lca(int x,int y){
31 if (dep[x]<dep[y])swap(x,y);
32 for(int i=15;i>=0;i--)
33 if (dep[f[x][i]]>=dep[y])x=f[x][i];
34 if (x==y)return x;
35 for(int i=15;i>=0;i--)
36 if (f[x][i]!=f[y][i]){
37 x=f[x][i];
38 y=f[y][i];
39 }
40 return f[x][0];
41 }
42 void div(int x,int y,vector<int>&v){
43 int p=15;
44 while ((1<<p)>dep[x]-dep[y]+1)p--;
45 v.push_back(id(x,p));
46 if (dep[x]-dep[y]+1==(1<<p))return;
47 int d=dep[y]+(1<<p)-1;
48 for(int i=15;i>=0;i--)
49 if (dep[f[x][i]]>=d)x=f[x][i];
50 v.push_back(id(x,p));
51 }
52 void dfs(int k,int fa,int s){
53 dep[k]=s;
54 f[k][0]=fa;
55 for(int i=1;i<=15;i++)f[k][i]=f[f[k][i-1]][i-1];
56 for(int i=0;i<v[k].size();i++)
57 if (v[k][i]!=fa)dfs(v[k][i],k,s+1);
58 }
59 void add(int x,int y,int z){
60 edge[E].nex=head[x];
61 edge[E].to=y;
62 edge[E].len=z;
63 head[x]=E++;
64 }
65 void dij(int s){
66 memset(d,oo,sizeof(d));
67 d[s]=0;
68 q.push(mp(0,s));
69 while (!q.empty()){
70 int k=q.top().second;
71 q.pop();
72 if (vis[k])continue;
73 vis[k]=1;
74 for(int i=head[k];i!=-1;i=edge[i].nex)
75 if (d[edge[i].to]>d[k]+edge[i].len){
76 d[edge[i].to]=d[k]+edge[i].len;
77 q.push(mp(-d[edge[i].to],edge[i].to));
78 }
79 }
80 }
81 int main(){
82 scanf("%d%d%d",&n,&m,&s);
83 for(int i=1;i<=n;i++)fa[i]=i;
84 for(int i=1;i<=m;i++){
85 scanf("%d%d%d",&a[i].p,&a[i].x1,&a[i].y1);
86 if (a[i].p==1)scanf("%d%d",&a[i].x2,&a[i].y2);
87 else{
88 if (check(a[i].x1,a[i].y1)){
89 merge(a[i].x1,a[i].y1);
90 v[a[i].x1].push_back(a[i].y1);
91 v[a[i].y1].push_back(a[i].x1);
92 }
93 }
94 scanf("%d",&a[i].w);
95 }
96 for(int i=1;i<=n;i++)
97 if (!f[i][0])dfs(i,i,0);
98 for(int i=1;i<=n;i++)fa[i]=i;
99 memset(head,-1,sizeof(head));
100 V=id(n,15);
101 for(int i=1;i<=n;i++){
102 add(id(i,0),id(i,0)+V,0);
103 add(id(i,0)+V,id(i,0),0);
104 }
105 for(int i=1;i<=n;i++)
106 for(int j=1;j<=15;j++){
107 add(id(i,j-1),id(i,j),0);
108 add(id(f[i][j-1],j-1),id(i,j),0);
109 add(id(i,j)+V,id(i,j-1)+V,0);
110 add(id(i,j)+V,id(f[i][j-1],j-1)+V,0);
111 }
112 for(int i=1;i<=m;i++){
113 if (a[i].p==2){
114 if (check(a[i].x1,a[i].y1)){
115 merge(a[i].x1,a[i].y1);
116 add(id(a[i].x1,0),id(a[i].y1,0)+V,a[i].w);
117 add(id(a[i].y1,0),id(a[i].x1,0)+V,a[i].w);
118 }
119 }
120 else{
121 if ((check(a[i].x1,a[i].y1))||(check(a[i].x2,a[i].y2)))continue;
122 vl.clear(),vr.clear();
123 int z=lca(a[i].x1,a[i].y1);
124 div(a[i].x1,z,vl);
125 div(a[i].y1,z,vl);
126 z=lca(a[i].x2,a[i].y2);
127 div(a[i].x2,z,vr);
128 div(a[i].y2,z,vr);
129 for(int x=0;x<vl.size();x++)
130 for(int y=0;y<vr.size();y++)add(vl[x],vr[y]+V,a[i].w);
131 }
132 }
133 dij(id(s,0));
134 for(int i=1;i<=n;i++){
135 int ans=d[id(i,0)+V];
136 if (ans==oo)ans=-1;
137 printf("%d ",ans);
138 }
139 }
[luogu5344]逛森林的更多相关文章
- 协议森林16 小美的桌号(DHCP协议)
作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. DHCP协议用于动态的配置电脑的网络相关参数,如主机的IP地址,路由器出口地址.DNS域名服务器地 ...
- scikit-learn随机森林调参小结
在Bagging与随机森林算法原理小结中,我们对随机森林(Random Forest, 以下简称RF)的原理做了总结.本文就从实践的角度对RF做一个总结.重点讲述scikit-learn中RF的调参注 ...
- Bagging与随机森林算法原理小结
在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合. ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- Step by step 如何创建一个新森林
原创地址:http://www.cnblogs.com/jfzhu/p/4006118.html 转载请注明出处 创建一个新森林就是在一台计算机上安装AD DS,并将这台计算机提升为域控制器. 演示环 ...
- [Machine Learning & Algorithm] 随机森林(Random Forest)
1 什么是随机森林? 作为新兴起的.高度灵活的一种机器学习算法,随机森林(Random Forest,简称RF)拥有广泛的应用前景,从市场营销到医疗保健保险,既可以用来做市场营销模拟的建模,统计客户来 ...
- 使用脚本自动配置matlab安装libsvm和随机森林工具箱
前言 支持向量机(SVM)和随机森林 都是用于分类的机器学习算法. 这里我需要对网上的工具箱在matlab中进行配置. 效果演示: 1.双击运行“自动配置.bat” 2.matlab会自动启动,手动配 ...
- 【BZOJ3669】[Noi2014]魔法森林 LCT
终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...
随机推荐
- 【Java虚拟机4】Java内存模型(硬件层面的并发优化基础知识--缓存一致性问题)
前言 今天学习了Java内存模型第一课的视频,讲了硬件层面的知识,还是和大学时一样,醍醐灌顶.老师讲得太好了. Java内存模型,感觉以前学得比较抽象.很繁杂,抽象. 这次试着系统一点跟着2个老师学习 ...
- Noip模拟20 2021.7.19
T1 玩具 题目读错意思直接报零... 拼接方式没读懂以为是个数学题,用卡特兰数,可是的确想多了 数据范围表达出你怎么暴力都行,选择$n^3,dp$ 相当于一片森林,每次多加一条边就合并成一棵树 在$ ...
- 21.6.25 test
\(NOI\) 模拟赛 \(T1\) 是树+位运算+dp+优化 打了 \(O(n^2)\) 的暴力dp,只拿到了35分,算了一下参赛的,人均65,中位数60.也能看出一些问题,对于一些模糊的猜测应该尝 ...
- Spring IOC:BeanDefinition加载注册流程(转)
BeanFactory接口体系 以DefaultListableBeanFactory为例梳理一下BeanFactory接口体系的细节 主要接口.抽象类的作用如下: BeanFactory(根据注册的 ...
- C++实现红黑树
红黑树的应用: 利用key_value对,快速查找,O(logn) socket与客户端id之间,形成映射关系(socket, id) 内存分配管理 一整块内存,不断分配小块 每分配一次,就加入到红黑 ...
- Spring源码分析-BeanFactoryPostProcessor
Spring源码分析-BeanFactoryPostProcessor 博主技术有限,本文难免有错误的地方,如果您发现了欢迎评论私信指出,谢谢 BeanFactoryPostProcessor接口是S ...
- 助你上手Vue3全家桶之VueX4教程
目录 1,前言 2,State 2.1,直接使用 2.2,结合computed 3,Getter 3.1,直接使用 3.2,结合computed 4,Mutation 4.1,直接使用 4.2,结合c ...
- Linux调整时区和同步时间
1.调整时区 tzselect 选择Asia -> China -> Beijing Time 2.设置为默认时区 cp -f /usr/share/zoneinfo/Asia/Shang ...
- 大型DELETE(删除大量数据)的一种解决方案
通过执行单条DELETE语句来删除一个大型的数据集会有以下的缺点: 1.DELETE语句的操作要被完整地记录到日志中,这要求在事务日志中要有足够的空间以完成整个事务: 2.在删除操作期间(可能会花费很 ...
- 手把手教你学Dapr - 4. 服务调用
上一篇:手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序 介绍 通过使用服务调用,您的应用程序可以使用标准的gRPC或HTTP协议与其他应用程序可靠.安全地通信. 为什么不直接用Ht ...