洛谷1967货车运输
生活随笔
收集整理的這篇文章主要介紹了
洛谷1967货车运输
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題目:https://www.luogu.org/problemnew/show/P1967
倍增LCA裸題。用了在線。還有離線O(n)做法、樹鏈剖分做法,暫不管了。
(自己程序的)坑點(diǎn):1.xnt從1開(kāi)始!2.數(shù)組大小!!!
重邊在最大生成樹的時(shí)候就解決啦~
不然我就要進(jìn)了子節(jié)點(diǎn)的dfs以后遍歷一遍它的邊,從與fa相連者中找出最大的作為mn[ ][0]的值;用vis標(biāo)記使fa再走到自己時(shí)不進(jìn)dfs了。
值得注意的地方是它可能是一個(gè)森林。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=1e5+5,M=5e5+5,lm=17;const ll INF=0x7fffffff; int n,m,head[N],xnt=1,dep[N],pre[N][lm+5],q; ll mn[N][lm+5],fa[N]; bool use[M<<1],in[N]; struct Edge{int next,from,to,bh;ll w;Edge(int n=0,int f=0,int t=0,int b=0,ll w=0):next(n),from(f),to(t),bh(b),w(w) {} }edge[M<<1],tp[N<<1]; bool cmp(Edge a,Edge b){return a.w>b.w;} int find(int a) {if(fa[a]==a)return a;return fa[a]=find(fa[a]); } void kruskal() {memcpy(tp,edge,sizeof tp);sort(tp+1,tp+xnt+1,cmp);for(int i=1,u,v,k;i<=xnt;i++)if(find(u=tp[i].from)!=find(v=tp[i].to))fa[find(u)]=find(v),use[k=tp[i].bh]=use[k^1]=1; } void dfs(int cur,int fa) {pre[cur][0]=fa;dep[cur]=dep[fa]+1;for(int i=1;i<=lm;i++){int k=pre[cur][i-1];//不是i>>1 if(!pre[k][i-1])break;pre[cur][i]=pre[k][i-1];mn[cur][i]=min(mn[cur][i-1],mn[k][i-1]);//不用賦初值了 }for(int i=head[cur],v;i;i=edge[i].next)if(use[i]&&(v=edge[i].to)!=fa)mn[v][0]=edge[i].w,dfs(v,cur); } ll lca(int x,int y) {ll ans=INF;if(dep[x]<dep[y])swap(x,y);int d=dep[x]-dep[y];for(int i=lm;i>=0;i--)// if(d&(1<<i)){ans=min(ans,mn[x][i]);x=pre[x][i];}if(x==y)return ans;// for(int i=lm;i>=0;i--)if(pre[x][i]!=pre[y][i]){ans=min(ans,min(mn[x][i],mn[y][i]));x=pre[x][i];y=pre[y][i];}return min(ans,min(mn[x][0],mn[y][0])); } int main() {scanf("%d%d",&n,&m);int x,y;ll z;for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=m;i++){scanf("%d%d%lld",&x,&y,&z);edge[++xnt]=Edge(head[x],x,y,xnt,z);head[x]=xnt;edge[++xnt]=Edge(head[y],y,x,xnt,z);head[y]=xnt;}kruskal();for(int i=1;i<=n;i++)if(fa[i]==i)dfs(i,0);//森林 // for(int j=1;j<=lm;j++) // for(int i=1;i<=n;i++) // { // mn[i][j]=min(mn[pre[i][j-1]][j-1],mn[i][j-1]); // pre[i][j]=pre[pre[i][j-1]][j-1]; // }scanf("%d",&q);for(int i=1;i<=q;i++){scanf("%d%d",&x,&y);if(find(x)!=find(y))printf("-1\n");else printf("%lld\n",lca(x,y));} }?
轉(zhuǎn)載于:https://www.cnblogs.com/Narh/p/8886782.html
總結(jié)
以上是生活随笔為你收集整理的洛谷1967货车运输的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 为何腾讯元宝要吸引开发者?
- 下一篇: 如何将腾讯元宝集成到自己的应用中?