题目链接:点击查看

题目大意:给出一个由n个节点组成的无向图,现在给出m次询问,每次询问给出一组u和v,问若使用u-v这条边所能组成的最小生成树的权值是多少

题目分析:题意描述的很清楚,但当然不能直接根据题意模拟,因为肯定会超时。。一次Kruskal算法的时间复杂度是O(边数),如果进行m次的话,时间复杂度就是m*边数,两项都拉满的话也得1e10了,肯定是不行的,那么我们该怎么办呢?最小生成树的话是用n-1条边,来连接n个点,所以我们可以一开始就求一次最小生成树,然后分为两种情况讨论:

  1. 若询问的u-v这条边在最小生成树上,那么答案就是最小生成树的值
  2. 若询问的u-v这条边不在最小生成树上,那么若我们在最小生成树中连上u-v这条边的话,肯定会形成环,若想变成树的话,就必须从u-v上断开一条边,根据题意我们要求最小的权值,所以断开的那条边的权值显然要尽可能大才行

综上所述,先把最小生成树剖一下然后直接线段树维护最大值就行了

写这个题花了10分钟,调了一晚上,还是因为代码写的不够多,写模板没有练成肌肉记忆的效果,导致三番五次的犯低级错误,让自己气急败坏却束手无策,多做题才是硬道理,像树链剖分树上倍增的模板应该越写越熟才行,说白了还是做题少,得继续努力啊

代码:

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;int n,m;struct Node
{int to,w;Node(int TO,int W){to=TO;w=W;}
};vector<Node>node[N];//邻接表 struct Edge
{int u,v,w;bool operator<(const Edge& a)const{return w<a.w;}
}edge[N<<1];//存边 map<pair<int,int>,bool>vis;//记录最小生成树中的边 map<pair<int,int>,int>vis2;//记录每个边的权值 pair<int,int> mp(int a,int b)
{return make_pair(a,b);
}int f[N];//并查集用 int find(int x)
{return x==f[x]?x:f[x]=find(f[x]);
}int Kruskal()
{for(int i=1;i<=n;i++)f[i]=i;sort(edge+1,edge+1+m);int cnt_edge=0;int sum=0;for(int i=1;i<=m;i++){int u=edge[i].u;int v=edge[i].v;int w=edge[i].w;int uu=find(u);int vv=find(v);if(uu!=vv){f[uu]=vv;sum+=w;vis[mp(u,v)]=vis[mp(v,u)]=true;node[u].push_back(Node(v,w));node[v].push_back(Node(u,w));cnt_edge++;if(cnt_edge==n-1)break;}}return sum;
}int deep[N],son[N],fa[N],num[N],val[N];//val[节点]=权值 void dfs1(int u,int f,int dep)
{deep[u]=dep;fa[u]=f;son[u]=-1;num[u]=1;for(auto i:node[u]){int v=i.to;int w=i.w;if(v==f)continue;dfs1(v,u,dep+1);val[v]=w;num[u]+=num[v];if(son[u]==-1||num[son[u]]<num[v])son[u]=v;}
}int top[N],id[N],idd[N],cnt;//id[节点]=编号 idd[编号]=节点 void dfs2(int u,int f,int root)
{top[u]=root;id[u]=++cnt;idd[cnt]=u;if(son[u]!=-1)dfs2(son[u],u,root);for(auto i:node[u]){int v=i.to;if(v==f||v==son[u])continue;dfs2(v,u,v);}
}struct tree
{int l,r,mmax;
}tree[N<<2];void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;if(l==r){tree[k].mmax=val[idd[l]];return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
}int query(int k,int l,int r)
{if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmax;return max(query(k<<1,l,r),query(k<<1|1,l,r));
}int solve(int a,int b)
{int mmax=0;while(top[a]!=top[b]){if(deep[top[a]]<deep[top[b]])swap(a,b);mmax=max(mmax,query(1,id[top[a]],id[a]));a=fa[top[a]];}if(a==b)return mmax;if(deep[a]>deep[b])swap(a,b);mmax=max(mmax,query(1,id[a]+1,id[b]));return mmax;
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);vis2[mp(edge[i].u,edge[i].v)]=edge[i].w;vis2[mp(edge[i].v,edge[i].u)]=edge[i].w;}int sum=Kruskal();dfs1(1,0,0);dfs2(1,0,1);build(1,1,n);int w;scanf("%d",&w);while(w--){int u,v;scanf("%d%d",&u,&v);if(vis[mp(u,v)])printf("%d\n",sum);elseprintf("%d\n",sum+vis2[mp(u,v)]-solve(u,v));}return 0;
}

Gym - 101889I Imperial roads(最小生成树+树链剖分+线段树)相关推荐

  1. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  2. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  4. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  7. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  8. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. Simulink触发子系统使用方法
  2. 【Python】使用 eval 实现反射
  3. oracle非常量不能用于privot_Oracle 行列转换函数pivot、unpivot的使用(二)
  4. 初识:如何实现利用C语言代码封装成可以安装的windows软件?
  5. url 编码 js url传参中文乱码解决方案
  6. vue 查看变量类型_Vue学习 开始走向VUE开发2---插值使用详解
  7. grep命令_「Linux」- ps -ef |grep 命令
  8. 解析6种常用View 的滑动方法
  9. DNS数据配置文件SOA和NS
  10. 【深入浅出图像算法】图像处理算法入门好文
  11. matlab编译后方交会,摄影测量——后方交会(matlab
  12. 《上古卷轴5:天际》控制台代码之配料药剂
  13. SHA1摘要算法(带示例)
  14. 网站注册登录等短信验证码
  15. g.SetGDIHigh()错误
  16. 新浪微博开放平台账号申请(基于dcloud开发)
  17. 驰骋BPM系统-表单引擎-流程引擎2020年大换装
  18. python开源框架排行_Python开源项目最新月榜TOP 10
  19. LiveNVR直播拉流转码无插件直播流媒体服务如何配置视频流水印视频上面添加水印
  20. python初学往哪个方向比较容易_学习Python应该往哪个方向发展?

热门文章

  1. SpringSecurity remember功能持久化token信息
  2. 再探ChannelPipeline 的初始化
  3. 接口方法和映射器的statement id 是怎么绑定起来的?
  4. 通过一个图来简单描述一下 socket 链接建立以及通信的模型
  5. HTTP协议通信原理
  6. 数据库问题解决后,应用面对的挑战
  7. FileItem API详解及演示
  8. Hive的基本操作-创建表的格式
  9. shiro认证与授权:自定义realm
  10. ES6新特性之函数优化-函数属性简写、箭头函数和解构表达式结合使用