JZOJ.5287【NOIP2017模拟8.16】最短路
容易发现这是一张仙人掌图(每条边最多属于一个环的无向连通图)
仙人掌图求最短路的常用处理方法是将它变成一棵树,原图里为环的点更改为该环上的点都指向该环的某个点A,然后边长就是该点到点A的最短路径。
再预处理每个点到顶点的距离dis。
然后对于询问的两个点u,v,如果u,v的LCA不在环上,那么距离就直接是dis[u]+dis[v]-2*dis[LCA(u,v)].
如果在环上,那么对于它们进入环的点Cu,Cv则有两种走法,一种是从Cu顺时针走向Cv,另一种是从Cu逆时针走向Cv,两者取最小再加上dis[u]+dis[v]-dis[Cu]-dis[Cv]就可以了。
至于求环,我们可以运用Tarjan的思想。求LCA用倍增就可以了。值得注意的是,这里可以一个点在两个环里。
1 #include <cstring> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <iostream> 5 #include <algorithm> 6 #include <cmath> 7 #define N 400005 8 using namespace std; 9 struct data{ 10 int next,to,power; 11 }l1[N],l2[N]; 12 int n,m,q,f1[N/2],f2[N/2],dfn[N/2],num1,num2,head1[N],head2[N],zhan[N],top,up[N][21],t,deep[N],dis[N/2],belong[N],f[N/2],visit[N/2],host[N/2],cnt; 13 int read(){ 14 int x=0,w=1; 15 char c=0; 16 for (c=getchar();c<'0'||c>'9';c=getchar()) {if (c=='-') w=-1;} 17 for (;c>='0'&&c<='9';c=getchar()) x=(x<<3)+(x<<1)+c-'0'; 18 return x*w; 19 } 20 void write(long long x){ 21 if (!x) putchar('0');else{ 22 char s[100]; 23 int i,j=0; 24 for (;x>0;x/=10) s[j++]=x%10; 25 for (i=j-1;i>=0;i--) putchar(s[i]+48); 26 } 27 putchar('\n'); 28 } 29 void add1(int u,int v,int w){ 30 num1++; 31 l1[num1].next=head1[u]; 32 l1[num1].to=v; 33 l1[num1].power=w; 34 head1[u]=num1; 35 num1++; 36 l1[num1].next=head1[v]; 37 l1[num1].to=u; 38 l1[num1].power=w; 39 head1[v]=num1; 40 } 41 void add2(int u,int v,int w){ 42 num2++; 43 l2[num2].next=head2[u]; 44 l2[num2].to=v; 45 l2[num2].power=w; 46 head2[u]=num2; 47 num2++; 48 l2[num2].next=head2[v]; 49 l2[num2].to=u; 50 l2[num2].power=w; 51 head2[v]=num2; 52 } 53 void DFS(int x){ 54 dfn[x]=++t; 55 for (int v=0,i=head1[x];i;i=l1[i].next){ 56 v=l1[i].to; 57 if ((v!=f[x])&&(!dfn[v])){ 58 f[v]=x; 59 zhan[++top]=i; 60 DFS(v); 61 } 62 else if ((v!=f[x])&&(dfn[v]<dfn[x])){ 63 long long sum=l1[i].power; 64 int p=top; 65 while ((l1[zhan[p]].to!=v)&&(p)){ 66 f1[l1[zhan[p]].to]=sum; 67 sum+=l1[zhan[p]].power; 68 p--; 69 } 70 cnt++; 71 sum=l1[zhan[p+1]].power; 72 for (int j=p+1;j<=top;++j){ 73 f2[l1[zhan[j]].to]=sum; 74 host[l1[zhan[j]].to]=v; 75 belong[l1[zhan[j]].to]=cnt; 76 add2(v,l1[zhan[j]].to,min(f1[l1[zhan[j]].to],f2[l1[zhan[j]].to])); 77 sum+=l1[zhan[j+1]].power; 78 } 79 } 80 } 81 top--; 82 } 83 void build(int x){ 84 visit[x]=1; 85 for (int v=0,i=head1[x];i;i=l1[i].next){ 86 v=l1[i].to; 87 if ((!visit[v])&&(v!=f[x])){ 88 if (((belong[x]!=belong[v])||((!belong[x])&&(!belong[v])))&&(host[x]!=v)&&(host[v]!=x)) 89 add2(x,v,l1[i].power); 90 build(v); 91 } 92 } 93 } 94 void pre(int x){ 95 deep[x]=deep[f[x]]+1; 96 up[x][0]=f[x]; 97 for (int i=1;i<=20;++i) 98 up[x][i]=up[up[x][i-1]][i-1]; 99 for (int v=0,i=head2[x];i;i=l2[i].next){ 100 v=l2[i].to; 101 if ((!deep[v])&&(v!=f[x])) { 102 f[v]=x; 103 dis[v]=dis[x]+l2[i].power; 104 pre(v); 105 } 106 } 107 } 108 int lca(int u,int v,int www){ 109 int a=u,b=v; 110 if (deep[u]<deep[v]) swap(u,v); 111 for (int i=20;i>=0;--i) 112 if (deep[v]<=deep[up[u][i]]) 113 u=up[u][i]; 114 if (u==v) return (dis[a]-dis[u]+dis[b]-dis[v]); 115 for (int i=20;i>=0;--i) 116 if (up[v][i]!=up[u][i]){ 117 v=up[v][i]; 118 u =up[u][i]; 119 } 120 if ((u!=v)&&(belong[u])&&(belong[u]==belong[v])) return (dis[a]-dis[u]+dis[b]-dis[v]+min(min(f1[u]+f2[v],f1[v]+f2[u]),min(abs(f1[u]-f1[v]),abs(f2[u]-f2[v])))); 121 else return (dis[a]-dis[up[u][0]]+dis[b]-dis[up[v][0]]); 122 } 123 int main(){ 124 n=read(),m=read(),q=read(); 125 t=0,num1=0,num2=0,top=0,cnt=0; 126 for (int v=0,u=0,w=0,i=1;i<=m;++i){ 127 u=read(),v=read(),w=read(); 128 add1(u,v,w); 129 } 130 deep[1]=-1; 131 f[1]=1; 132 dis[1]=0; 133 DFS(1); 134 build(1); 135 f[1]=1; 136 pre(1); 137 for (int u=0,v=0,i=1;i<=q;++i){ 138 u=read(),v=read(); 139 write(lca(u,v,i)); 140 } 141 return 0; 142 }
拖欠了好几天的题终于A了QAQ