BZOJ2125: 最短路
来源:互联网 发布:zola算法美队2 编辑:程序博客网 时间:2024/05/29 06:31
建出圆方树
对于询问的两个点,倍增找他们的LCA
若是圆点,直接得到答案
若是方点,两边的点先跳到这个环上,然后找环上的最近距离
code:
#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long long#define inf 1e9using namespace std;inline void down(int &x,const int &y){if(x>y)x=y;}const int maxn = 41000;const int maxd = 17;int n,m,q;struct edge{ int y,c,nex; edge(){} edge(const int _y,const int _c,const int _nex){y=_y;c=_c;nex=_nex;}}a[maxn<<1],b[maxn<<1]; int len,fir[maxn],len2,fir2[maxn];inline void ins(const int x,const int y,const int c){a[++len]=edge(y,c,fir[x]);fir[x]=len;}inline void ins2(const int x,const int y,const int c){b[++len2]=edge(y,c,fir2[x]);fir2[x]=len2;}vector<int>V[maxn]; int cnt,fa[maxn];int T[maxn],tp;int did,dfn[maxn],low[maxn];void tarjan(const int x,const int pre){ dfn[x]=low[x]=++did; T[++tp]=x; for(int k=fir[x];k;k=a[k].nex) if(k!=(pre^1)) { const int y=a[k].y; if(!dfn[y]) { tarjan(y,k); down(low[x],low[y]); if(low[y]==dfn[x]) { fa[++cnt]=x; V[cnt].push_back(x); int la=0; while(la!=y) V[cnt].push_back(la=T[tp--]); } else if(low[y]>dfn[x]) tp--; } else down(low[x],dfn[y]); }}bool ev[maxn];void dfs(const int x){ ev[x]=true; for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(dfn[y]>dfn[x]) { if(low[y]>dfn[x]) ins2(x,y,a[k].c),ins2(y,x,a[k].c); if(!ev[y]) dfs(y); }}int use[maxn],ci[maxn],ed;void dfs2(const int x){ for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(use[y]>use[x]) { if(use[x]==1) { if(use[y]==ed) ci[ed]=a[k].c; else ci[1]=a[k].c; if(use[y]==ed) continue; } else ci[use[x]]=a[k].c; dfs2(y); }}int s[maxn],pres[maxn],pid[maxn],sum[maxn];void build(){ dfs(1); for(int i=1;i<=cnt;i++) { for(int j=0;j<V[i].size();j++) use[V[i][j]]=j+1; ed=V[i].size(); if(ed==2) { int x=V[i][0],ct=0; for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(use[y]) { if(!ct) ci[1]=a[k].c; else ci[2]=a[k].c; ct++; } } else dfs2(fa[i]); for(int j=1;j<=ed;j++) s[j]=s[j-1]+ci[j]; sum[i]=s[ed]; for(int j=0;j<V[i].size();j++) { int c=min(s[j],s[ed]-s[j]); ins2(n+i,V[i][j],c); ins2(V[i][j],n+i,c); } for(int j=1;j<V[i].size();j++) pid[V[i][j]]=j+1,pres[V[i][j]]=s[j]; for(int j=0;j<V[i].size();j++) use[V[i][j]]=0; }}int f[maxn][maxd],dis[maxn][maxd],dep[maxn];void build_tree(const int x){ for(int i=1;i<maxd;i++) f[x][i]=f[f[x][i-1]][i-1], dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1]; for(int k=fir2[x],y=b[k].y;k;k=b[k].nex,y=b[k].y) if(y!=f[x][0]) dep[y]=dep[x]+1,f[y][0]=x,dis[y][0]=b[k].c,build_tree(y);}void lca(int x,int y,int &top,int &L){ if(dep[x]<dep[y]) swap(x,y); for(int i=maxd-1;i>=0;i--) if(dep[x]-dep[y]>=(1<<i)) L+=dis[x][i],x=f[x][i]; if(x==y) { top=x; return; } for(int i=maxd-1;i>=0;i--) if(f[x][i]!=f[y][i]) L+=dis[x][i],x=f[x][i], L+=dis[y][i],y=f[y][i]; L+=dis[x][0]+dis[y][0]; top=f[x][0];}int main(){ scanf("%d%d%d",&n,&m,&q); len=1; for(int i=1;i<=m;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); ins(x,y,c); ins(y,x,c); } did=cnt=0; tarjan(1,0); len2=0; build(); dep[1]=1; build_tree(1); int ti=0; while(q--) { ++ti; int x,y; scanf("%d%d",&x,&y); int top,l=0; lca(x,y,top,l); if(top>n) { l=0; for(int i=maxd-1;i>=0;i--) if(dep[x]-(dep[top]+1)>=(1<<i)) l+=dis[x][i],x=f[x][i]; swap(x,y); for(int i=maxd-1;i>=0;i--) if(dep[x]-(dep[top]+1)>=(1<<i)) l+=dis[x][i],x=f[x][i]; if(pid[x]>pid[y]) swap(x,y); l+=min(pres[y]-pres[x],sum[top-n]-pres[y]+pres[x]); printf("%d\n",l); } else printf("%d\n",l); } return 0;}
阅读全文
0 0
- BZOJ2125: 最短路
- [BZOJ2125][仙人掌]最短路
- BZOJ2125: 最短路
- 【BZOJ2125】【仙人掌】最短路 题解
- bzoj3047: Freda的传呼机&bzoj2125: 最短路
- 最短路 & 次短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- Python 正则表达式匹配字符串替换、格式修改
- [agc14e]Blue and Red Tree
- vim替换命令
- HDU1050-Moving Table
- 用jquery制作轮播图
- BZOJ2125: 最短路
- linux基础练习
- HTML知识点总结
- POJ 1743 Musical Theme(不可重叠最长重复子串 后缀数组)
- C#分页Dome
- 条件语句及循环语句基础
- hdu 1255 覆盖的面积
- Python 基础教程
- Partition List