YbtOJ#631-次短路径【左偏树,最短路】
正題
題目鏈接:https://www.ybtoj.com.cn/contest/114/problem/1
題目大意
給出nnn個點mmm條邊的一張無向圖,對于每個點iii求不經(jīng)過i~1i\sim 1i~1的最短路的第一條邊的情況下iii到111的最短路
數(shù)據(jù)保證這條邊唯一
n∈[1,105],m∈[1,2×105],c∈[1,103]n\in[1,10^5],m\in[1,2\times 10^5],c\in[1,10^3]n∈[1,105],m∈[1,2×105],c∈[1,103]
解題思路
因為保證的那個東西,所以圖的最短路樹真的是一棵樹了,所以先跑出最短路樹考慮在最短路樹上面搞。
然后題目限制了我們不能從樹上的祖先那條邊過來,這樣就分為了兩種情況。一種是從該點的子樹外面連過來的邊,另一種是從子樹中走上來的邊。第二種很麻煩,因為子樹的最短路是用該節(jié)點的最短路擴展的,所以不能直接使用。
考慮一條非樹邊(x,y)(x,y)(x,y),這條邊會擴展一條disy+wdis_y+wdisy?+w到xxx的路徑。(disxdis_xdisx?表示1~x1\sim x1~x的最短路)。
并且這條邊可以使用到LCA(x,y)LCA(x,y)LCA(x,y)處,此時xxx的祖先們都不包含yyy在子樹內(nèi),可以直接用yyy的子樹擴展。
所以可以維護一個左偏樹,每次合并兩個兒子的信息,如果堆頂?shù)倪呅枰粍h除就刪除。需要寫一個lazylazylazy標記來修改整棵樹
時間復雜度O(nlog?n)O(n\log n)O(nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define mp(x,y) make_pair(x,y) using namespace std; const int N=4e5+10; struct point{int val,x,y;point(int v=0,int xx=0,int yy=0){val=v;x=xx;y=yy;return;} }; bool operator<(point x,point y) {return x.val<y.val;} struct Heap{point val[N];int t[N][2],lazy[N],dis[N];void Downdata(int x){if(!lazy[x])return;int ls=t[x][0],rs=t[x][1];lazy[ls]+=lazy[x];lazy[rs]+=lazy[x];val[ls].val+=lazy[x];val[rs].val+=lazy[x];lazy[x]=0;return;}int Merge(int x,int y){Downdata(x);Downdata(y);if(!x||!y)return x+y;if(val[y]<val[x])swap(x,y);int &ls=t[x][0],&rs=t[x][1];rs=Merge(rs,y);if(dis[rs]>dis[ls])swap(ls,rs);dis[x]=dis[rs]+1;return x;}int Del(int x){int &ls=t[x][0],&rs=t[x][1];val[x]=0;return Merge(ls,rs);} }T; struct node{int to,next,w; }a[N]; int n,m,tot,cnt,num,ls[N],f[N]; int rfn[N],p[N],ans[N]; bool v[N];vector<int> G[N]; priority_queue<pair<int,int> >q; void addl(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;return; } void dij(){memset(f,0x3f,sizeof(f));q.push(mp(0,1));f[1]=0;while(!q.empty()){int x=q.top().second;q.pop();if(v[x])continue;v[x]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[x]+a[i].w<f[y]){f[y]=f[x]+a[i].w;q.push(mp(-f[y],y));}}}return; } void dfs(int x){rfn[x]=++cnt;for(int i=0;i<G[x].size();i++){int y=G[x][i];dfs(y);T.val[p[y]].val+=f[y]-f[x];T.lazy[p[y]]+=f[y]-f[x];p[x]=T.Merge(p[x],p[y]);}for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[x]+a[i].w==f[y])continue;if(f[y]+a[i].w==f[x])continue;T.val[++num]=point(f[y]+a[i].w,x,y);p[x]=T.Merge(p[x],num);}while(1){if(!p[x]){ans[x]=-1;break;}point w=T.val[p[x]];if(rfn[w.y]>=rfn[x]){p[x]=T.Del(p[x]);continue;}ans[x]=w.val;break;}return; } int main() {freopen("pal.in","r",stdin);freopen("pal.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);addl(x,y,w);addl(y,x,w);}dij();for(int x=1;x<=n;x++)for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[x]+a[i].w==f[y])G[x].push_back(y);}dfs(1);for(int i=2;i<=n;i++)if(!ans[i])puts("-1");else printf("%d\n",ans[i]);return 0; }總結(jié)
以上是生活随笔為你收集整理的YbtOJ#631-次短路径【左偏树,最短路】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 东莞外贸怎么赚钱(东莞外贸怎么赚钱的)
- 下一篇: YbtOJ#893-带权的图【高斯消元,