Codeforces Round 1043 (Div. 3) F. Rada and the Chamomile Valley
F.拉达和甘菊谷
每次测试的时间限制:3 秒
每次测试的内存限制512 兆字节
输入:标准输入
输出:标准输出
昨天,拉达发现了一个传送门,可以把她传送到洋甘菊谷,然后再传送回来。拉达的快乐无以言表,但好景不长–她突然意识到,她不知道任何一个斯迈沙里奇人会在何时何地出现。
甘菊谷由 nnn 座房子和连接房子的 mmm 条巷子组成。小巷的编号从 111 到 mmm 。您可以沿着小巷双向行走。众所周知,从任何一栋房子出发,都可以通过小巷到达其他任何一栋房子。此外,任何两栋房子最多只有一条巷子相连。
拉达知道 Smeshariki 每天都会从 111 号房屋步行到 nnn 号房屋,但她不知道他们具体会走哪条巷子。在接下来的 qqq 天里,拉达每天都会去甘菊谷。在 kkk 这一天,她会去 ckc_kck 号房子。
由于拉达不知道斯梅斯哈里基会走哪条具体的巷子,所以她只对那些他们***肯定会走的巷子感兴趣。为了确保不会错过任何一条,她想知道每天最近的此类车道的索引。拉达忙于漫步甘菊谷,所以她请您帮她确定所需的车道指数。
从房屋 ccc 到连接房屋 aaa 和 bbb 的车道的距离定义为 ρ(a,c)\rho(a, c)ρ(a,c) 和 ρ(b,c)\rho(b, c)ρ(b,c) 的最小值,其中 ρ(a,b)\rho(a, b)ρ(a,b) 是指从房屋编号 aaa 开始到达房屋编号 bbb 所需的最小车道数。
输入
输入的第一行包含一个整数 ttt ( 1≤t≤1041 \leq t \leq 10^41≤t≤104 ) - 测试用例的数量。每个测试用例的说明如下。
第一行包含两个整数 nnn 和 mmm ( 1≤n≤2⋅1051 \leq n \leq 2 \cdot 10^51≤n≤2⋅105 , n−1≤m≤min(n⋅(n−1)2,2⋅105)n-1 \leq m \leq \min(\frac{n \cdot (n-1)}{2}, 2 \cdot 10^5)n−1≤m≤min(2n⋅(n−1),2⋅105) )–分别是房屋和车道的数量。
接下来的 mmm 行包含两个整数 u≠vu \neq vu=v ( 1≤u,v≤n1 \leq u, v \leq n1≤u,v≤n )–连接编号为 uuu 和 vvv 的房屋的车道。这些巷道是按编号顺序排列的,即先描述第一条巷道,然后是第二条、第三条,依次类推,直到 mmm /第三条巷道。
接下来是一个整数 qqq ( 1≤q≤2⋅1051 \leq q \leq 2 \cdot 10^51≤q≤2⋅105 )–拉达将在甘菊谷行走的天数。
接下来的 qqq 行每行都包含一个整数 ccc ( 1≤c≤n1 \leq c \leq n1≤c≤n )–拉达当天将在哪所房子里。
可以保证的是,从任何一栋房子出发,只需通过小巷就可以到达其他任何一栋房子,而从一栋房子到它自己之间是没有小巷的,任何两栋房子之间最多只有一条小巷相连。
保证所有测试用例的 nnn 之和不超过 2⋅1052 \cdot 10^52⋅105 ,所有测试用例的 mmm 之和不超过 2⋅1052 \cdot 10^52⋅105 ,所有测试用例的 qqq 之和不超过 2⋅1052 \cdot 10^52⋅105 。
输出
对于每个测试用例,输出每一天的答案。如果任何一天都有多条合适的车道,则输出合适车道中指数小的车道。如果没有所需的车道,则输出 −1-1−1 。
注
在所有进一步的解释中,我们将 aaa 号房屋经由 ccc 号巷道到 bbb 号房屋的过渡段称为 a→cba \xrightarrow{c} bacb 。
在第一个样本中,从房屋 111 到房屋 333 ,至少可以通过以下路径到达:
1→33 1 \xrightarrow{3} 3 133
1→12→23 1 \xrightarrow{1} 2 \xrightarrow{2} 3 11223
我们可以看到,这两条路径没有共用车道,也就是说没有合适的车道。
在第二个样本中,我们可以看到从 111 到 nnn 有一条唯一的路径:
1→12→23→34→45 1 \xrightarrow{1} 2 \xrightarrow{2} 3 \xrightarrow{3} 4 \xrightarrow{4} 5 112233445
可以看出, vvv -顶点的答案是 max(v−1, 1)\max(v-1,\ 1)max(v−1, 1) 。
-
解决办法
- 1、首先我要知道这必经过路径是什么,在一图里面可以叫做桥,(不了解的先去看看怎么求,后面要用)。
- 2、他是去动物们的必经路径上,而且只能是1−n1 - n1−n的路径上,由于是桥,所以我们随便跑一条路,把上面的桥标记一下,这就是他要去的路径。
- 3、我们把要求路径求出来了,接下来我们可以去广搜,这样就只需O(1)O(1)O(1)时间复杂度输出每一个答案
- (启发式广搜):因为如果我们每个点去广搜整个图,最后一点会超爆,所以我们在广搜时,在遇到标记了的桥或标记了的桥的两点,就直接pop,因为从这两点出发的点肯定比当前点更优。我提供两份代码,一个判点,一个是判桥。(
一定不是我开始判桥错了,去判点,后面才把判边改出来) -
第一篇是判标记了的桥的两边点的
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,FULL=1e15;
struct node{int a,b,id;bool friend operator<(node aa,node bb){return aa.id<bb.id;}
}qiao[N];
int h[N],ans,to[N*2],ne[N*2],id[N*2],n,m,tot,q,dfn[N],low[N],sj;
int dp[N],dis[N],pre1[N],pre2[N];
bool vis[N],vis1[N],vis2[N];
void add(int a,int b,int c)
{tot++;ne[tot]=h[a];h[a]=tot;to[tot]=b;id[tot]=c;
}
void bfs(int u)
{queue<int>q;q.push(u);while(!q.empty()){int j=q.front();q.pop();if(vis2[j]&&j!=u)continue;for(int i=h[j];i;i=ne[i]){int jj=to[i];if(dis[jj]>dis[j]+1){dis[jj]=dis[j]+1;dp[jj]=dp[u];q.push(jj);}}}
}
void spfa(int u)
{vis[u]=1;queue<int>q;q.push(u);while(!q.empty()){int j=q.front();q.pop();// cout<<j<<" ";if(j==n)break;for(int i=h[j];i;i=ne[i]){int jj=to[i];if(!vis[jj]){pre1[jj]=j;pre2[jj]=id[i];q.push(jj);vis[jj]=1;}}}// cout<<'\n'<<"-----------"<<'\n';int jj=n;while(jj!=1){// cout<<jj<<" "<<pre2[jj]<<" ";vis1[pre2[jj]]=1;jj=pre1[jj];}// cout<<'\n'<<"-----------"<<'\n';
}
void tanjian(int u,int fa)
{dfn[u]=low[u]=++sj;for(int i=h[u];i;i=ne[i]){int j=to[i];if(!dfn[j]){tanjian(j,u);low[u]=min(low[u],low[j]);if(low[j]>dfn[u]&&vis1[id[i]]){vis2[u]=1;vis2[j]=1;qiao[++ans].a=u;qiao[ans].b=j;qiao[ans].id=id[i];// cout<<u<<" "<<j<<'\n';}}else if(j!=fa)low[u]=min(low[u],dfn[j]);}
}
signed main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _,a,b;cin>>_;while(_--){cin>>n>>m;fill(dfn+1,dfn+1+n,0);sj=0;ans=0;tot=0;fill(h+1,h+1+n,0);for(int i=1;i<=m;i++){cin>>a>>b;add(a,b,i);add(b,a,i);}// cout<<ans<<'\n';fill(dis+1,dis+1+n,FULL);fill(vis+1,vis+1+n,0);fill(vis2+1,vis2+1+n,0);fill(vis1+1,vis1+1+m,0);spfa(1);tanjian(1,0);// cout<<'\n';sort(qiao+1,qiao+1+ans);// cout<<qiao[1].id<<'\n';for(int i=1;i<=ans;i++){// cout<<qiao[i].id<<" "<<vis1[qiao[i].id]<<'\n';if(dis[qiao[i].a]>0)dp[qiao[i].a]=qiao[i].id,dis[qiao[i].a]=0,bfs(qiao[i].a);if(dis[qiao[i].b]>0)dp[qiao[i].b]=qiao[i].id,dis[qiao[i].b]=0,bfs(qiao[i].b);// bfs(qiao[i].a),bfs(qiao[i].b);}cin>>q;while(q--){cin>>a;if(dis[a]==FULL)cout<<"-1"<<" ";elsecout<<dp[a]<<" ";}cout<<'\n';}return 0;
}
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,FULL=1e15;
struct node{int a,b,id;bool friend operator<(node aa,node bb){return aa.id<bb.id;}
}qiao[N];
int h[N],ans,to[N*2],ne[N*2],id[N*2],n,m,tot,q,dfn[N],low[N],sj;
int dp[N],dis[N],pre1[N],pre2[N];
bool vis[N],vis1[N],vis2[N];
void add(int a,int b,int c)
{tot++;ne[tot]=h[a];h[a]=tot;to[tot]=b;id[tot]=c;
}
void bfs(int u)
{queue<int>q;q.push(u);while(!q.empty()){int j=q.front();q.pop();// if(vis2[j]&&j!=u)continue;for(int i=h[j];i;i=ne[i]){if(vis2[id[i]])continue;int jj=to[i];if(dis[jj]>dis[j]+1){dis[jj]=dis[j]+1;dp[jj]=dp[u];q.push(jj);}}}
}
void spfa(int u)
{vis[u]=1;queue<int>q;q.push(u);while(!q.empty()){int j=q.front();q.pop();// cout<<j<<" ";if(j==n)break;for(int i=h[j];i;i=ne[i]){int jj=to[i];if(!vis[jj]){pre1[jj]=j;pre2[jj]=id[i];q.push(jj);vis[jj]=1;}}}// cout<<'\n'<<"-----------"<<'\n';int jj=n;while(jj!=1){// cout<<jj<<" "<<pre2[jj]<<" ";vis1[pre2[jj]]=1;jj=pre1[jj];}// cout<<'\n'<<"-----------"<<'\n';
}
void tanjian(int u,int fa)
{dfn[u]=low[u]=++sj;for(int i=h[u];i;i=ne[i]){int j=to[i];if(!dfn[j]){tanjian(j,u);low[u]=min(low[u],low[j]);if(low[j]>dfn[u]&&vis1[id[i]]){vis2[id[i]]=1;qiao[++ans].a=u;qiao[ans].b=j;qiao[ans].id=id[i];// cout<<u<<" "<<j<<'\n';}}else if(j!=fa)low[u]=min(low[u],dfn[j]);}
}
signed main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _,a,b;cin>>_;while(_--){cin>>n>>m;fill(dfn+1,dfn+1+n,0);sj=0;ans=0;tot=0;fill(h+1,h+1+n,0);for(int i=1;i<=m;i++){cin>>a>>b;add(a,b,i);add(b,a,i);}// cout<<ans<<'\n';fill(dis+1,dis+1+n,FULL);fill(vis+1,vis+1+n,0);fill(vis2+1,vis2+1+m,0);fill(vis1+1,vis1+1+m,0);spfa(1);tanjian(1,0);// cout<<'\n';sort(qiao+1,qiao+1+ans);// cout<<qiao[1].id<<'\n';for(int i=1;i<=ans;i++){// cout<<qiao[i].id<<" "<<vis1[qiao[i].id]<<'\n';if(dis[qiao[i].a]>0)dp[qiao[i].a]=qiao[i].id,dis[qiao[i].a]=0,bfs(qiao[i].a);if(dis[qiao[i].b]>0)dp[qiao[i].b]=qiao[i].id,dis[qiao[i].b]=0,bfs(qiao[i].b);// bfs(qiao[i].a),bfs(qiao[i].b);}cin>>q;while(q--){cin>>a;if(dis[a]==FULL)cout<<"-1"<<" ";elsecout<<dp[a]<<" ";}cout<<'\n';}return 0;
}