17AHU排位赛2 A题(最小生成树、LCA维护树上路径)
来源:互联网 发布:龙门县平陵镇网络问政 编辑:程序博客网 时间:2024/06/05 17:15
problem
有一个n个点m条边的连通无向图(无重边、无自环),点的编号为1~n。每条边都有一个正的边权,并且每条边边权互不相同(即数据保证该图的最小生成树唯一)。
如果只是求最小生成树,那么Ohyee觉得太简单了,于是他决定考考你。
对于每条边(u,v)都进行询问:
——如果该边在最小生成树上,那么输出“Ohyee”;
——如果该边不在最小生成树上,那么输出最小生成树上u,v两点路径中边权的最小值。
Input
第一行输入两个整数n,m(2<=n<=100000,n-1<=m<=200000)
接下来m行,每行输入三个整数u,v,w。u,v表示该边连接点的编号,w是边权。
(1<=w<=1000000000)
Output
输出一共m行,按照输入的边的顺序回答每条边的询问。
Input
4 4
1 2 2
2 3 5
3 4 7
4 1 3
Output
Ohyee
Ohyee
2
Ohyee
Limitation
1s 256MB
Hint
原图最小生成树中的边是(1,2,2) (2,3,5) (4,1,3)
对于输入的第三条边(3,4,7),树上3->4的路径是3->2->1->4,边权分别是5,2,3,最小值是2。
思路
最小生成树和树上路径信息维护的结合,两个模板套在一起即可
代码示例
#include<bits/stdc++.h>using namespace std;const int maxn=1e5+50;const int maxm=2e5+50;const int inf=0x3fffffff;int n,m;//n为点数 m为边数struct eee{//解决lca int from,to,dist; eee(int u,int v,int w):from(u),to(v),dist(w){ }};vector<eee> edges;//边的具体信息vector<int> GG[maxn];//边的编号void addEdge(int u,int v,int w){//vector邻接表 edges.push_back(eee(u,v,w)); edges.push_back(eee(v,u,w)); int size=edges.size(); GG[u].push_back(size-2); GG[v].push_back(size-1);}const int maxlog=30;int grand[maxn][maxlog];int gmax[maxn][maxlog];int depth[maxn];int s;//倍增最大步数int root;//根节点void dfs(int x)//预处理{ for(int i=1;i<=s;++i){ grand[x][i]=grand[grand[x][i-1]][i-1]; gmax[x][i]=max(gmax[x][i-1],gmax[grand[x][i-1]][i-1]); if(!grand[x][i]) break; } for(int i=0;i<GG[x].size();i++){ eee & e=edges[GG[x][i]]; if(e.to!=grand[x][0]){ depth[e.to]=depth[x]+1; grand[e.to][0]=x; gmax[e.to][0]=e.dist; dfs(e.to); } }}void init(){ s=floor(log(n+0.0)/log(2.0)); depth[0]=-1; //memset(depth,0,sizeof(depth)); memset(grand,0,sizeof(grand)); memset(gmax,0,sizeof(gmax)); root=1; dfs(root);//以1为根结点建树}int lca(int a,int b,int &maxx)//最大值{ if(depth[a]>depth[b]) swap(a,b); maxx=gmax[b][0];//之前的bug,应该放更深的b int dre=depth[b]-depth[a]; for(int i=s;i>=0;--i){ if(dre&(1<<i)) maxx=max(maxx,gmax[b][i]),b=grand[b][i]; } if(a==b) return a; for(int i=s;i>=0;i--) if(grand[a][i]!=grand[b][i]){ maxx=max(maxx,gmax[a][i]),maxx=max(maxx,gmax[b][i]); a=grand[a][i],b=grand[b][i]; } maxx=max(maxx,gmax[a][0]); maxx=max(maxx,gmax[b][0]); return grand[a][0];}typedef struct{//边集数组 int beg; int endd; int weight; int flag;//1表示在 0表示不在 int order;//进来时的顺序}Edge;bool cmp(Edge a,Edge b)//边集数组排序{ return a.weight<b.weight;}bool cmp1(Edge a,Edge b)//原位置排序{ return a.order<b.order;}typedef struct{ Edge xiang[maxm];//边的信息 int numVertexes,numEdges;//顶点数和边数}MGraph;MGraph G;void CreateMGraph(){ for(int i=0;i<m;++i){ cin>>G.xiang[i].beg>>G.xiang[i].endd>>G.xiang[i].weight; G.xiang[i].order=i; } G.numEdges=m; G.numVertexes=n; sort(G.xiang,G.xiang+m,cmp);}int parent[maxm];//辅助并查集int Find(int f)//查找连线顶点的尾部下标{ return parent[f]!=f?parent[f]=Find(parent[f]):f;}void MiniSpanTree_Kruskal(){ int nn,mm; //int parent[maxm];//定义一数组用来判断边与边是否形成环路 for(int i=0;i<G.numVertexes;++i) parent[i]=i;//初始化数组值为i for(int i=0;i<G.numEdges;++i){//循环每一条边 nn=Find(G.xiang[i].beg); mm=Find(G.xiang[i].endd); if(nn!=mm){//假如n与m不等,说明此边没有与现有生成树形成环路 parent[nn]=mm;//将此边的结尾顶点放入下标为起点的parent中 //表示此顶点已经在生成树集合中 //printf("在:(%d,%d) %d\n",G.xiang[i].beg,G.xiang[i].endd,G.xiang[i].weight); //sum+=G.xiang[i].weight; G.xiang[i].flag=1; addEdge(G.xiang[i].beg,G.xiang[i].endd,1000000001-G.xiang[i].weight);//进入lca,注意求最小值,所以拿大值减后求最大值 //cout<<G.xiang[i].beg<<' '<<G.xiang[i].endd<<' '<<1000000001-G.xiang[i].weight<<endl; } else{ G.xiang[i].flag=0;//不在 } //else printf("不在:(%d,%d) %d\n",G.xiang[i].beg,G.xiang[i].endd,G.xiang[i].weight); } //cout<<sum<<endl;//路径和}int main(){ ios::sync_with_stdio(false); cin>>n>>m; CreateMGraph(); //for(int i=0;i<G.numEdges;++i) cout<<G.xiang[i].beg<<" "<<G.xiang[i].endd<<" "<<G.xiang[i].weight<<endl; //cout<<G.numEdges<<G.numVertexes<<endl; MiniSpanTree_Kruskal(); //for(int i=0;i<G.numVertexes;++i) //cout<<parent[i]<<' '; sort(G.xiang,G.xiang+m,cmp1); init(); int maxx;//生成树上两点间最短边权 for(int i=0;i<m;++i){ if(G.xiang[i].flag==1){ cout<<"Ohyee"<<endl; } else{ lca(G.xiang[i].beg,G.xiang[i].endd,maxx); //cout<<lca(u,v,maxx,sum)<<endl; cout<<1000000001-maxx<<endl;//再减去即为最小值 } } return 0;}
阅读全文
1 0
- 17AHU排位赛2 A题(最小生成树、LCA维护树上路径)
- 17AHU排位赛3 D题 旋转吧!雪月花 ! (DFS序,线段树维护树上最值)
- bzoj3732 Network 最小生成树+LCA+树上倍增
- 17AHU排位赛2 E题(树上最大匹配,树形DP)
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
- 【BZOJ 2588】Count on a tree 【树上路径第K大】【LCA+主席树】
- CodeForces 827D Round #423 Div2F&Div1D:LCA+路径压缩+MST(最小生成树)
- 过路费(最小生成树+lca)
- 最小生成树+LCA+uva11354
- <最小生成树><lca>Heatwave
- 17AHU排位赛3 A题 (逆康托展开)
- 17AHU排位赛2 F题(bitset优化)
- hdu 5723 (最小生成树 + 树上的期望)
- HDU 5723 (最小生成树/树上的期望)
- *树上倍增(LCA)
- 17AHU排位赛1 D题(线段树除2)
- SPOJ Count on a tree(lca+主席树,树上主席树,好题)
- SPOJ 10628. Count on a tree (树上第k大,LCA+主席树)
- HTML5学习笔记 —— JavaScript基础知识
- Jenkins之邮件通知
- 我的C#学习笔记1 -- 打印到控制台
- Spring Boot 实现 HTTPS
- javafx cell在初始化过程中如何获得其他列的值
- 17AHU排位赛2 A题(最小生成树、LCA维护树上路径)
- tensorflow运维(2):tensorboard:No scalar data was found,没有发现常量数据
- 为什么扫描枪只能扫入数字但是扫不进字母
- PAT甲级1003. Emergency (25)
- 指针方面的小问题
- 关于在n进制下,显示的等式成立。求当前进制。
- 古文觀止卷八_与于襄阳书_韓愈
- 每个程序员半小时内必须解决的5个编程问题——php实现
- 闭包的秘密