重要道路
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
给定一个无向图 G,对于其中的一条边(u,v),将它删除之后会使得从 1 到 n 的最短路长度增加,那么这条边被称为“重要道路”。
求 G 中所有的重要道路。
Input
第一行两个整数 n,m,分别代表点数和边数。
接下来 m 行,每行三个整数 u,v,c,代表权值为 c 的无向边(u,v)。可能有重 边,但没有自环。保证 1 号点和 n 号点是连通的。
Output
第一行一个整数 k,代表重要道路的数量。
下一行升序输出 k 个数代表重要道路的编号(按输入顺序从 1 到 m)。
Sample Input
6 7
1 2 1
2 3 1
2 5 3
1 3 2
3 5 1
2 4 1
5 6 2
Sample Output
2
5 7
Data Constraint
20%的数据,n,m<=10。
另外 20%的数据,m=n-1。
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
给定一个无向图 G,对于其中的一条边(u,v),将它删除之后会使得从 1 到 n 的最短路长度增加,那么这条边被称为“重要道路”。
求 G 中所有的重要道路。
Input
第一行两个整数 n,m,分别代表点数和边数。
接下来 m 行,每行三个整数 u,v,c,代表权值为 c 的无向边(u,v)。可能有重 边,但没有自环。保证 1 号点和 n 号点是连通的。
Output
第一行一个整数 k,代表重要道路的数量。
下一行升序输出 k 个数代表重要道路的编号(按输入顺序从 1 到 m)。
Sample Input
6 7
1 2 1
2 3 1
2 5 3
1 3 2
3 5 1
2 4 1
5 6 2
Sample Output
2
5 7
Data Constraint
20%的数据,n,m<=10。
另外 20%的数据,m=n-1。
100%的数据,1<=n<=20000,1<=m,c<=100000。
思路::先是最短路求出dis[]
然后什么样的路会可能是重要道路呢?
可以这么说,对于点i,有点j可以走到点i
若有d[i] == d[j] + EdgeValue[i][j]
那么边(i,j)可能是重要道路
我们把可能是重要道路的路扔进一个新图,然后在新图上找割边,问题就解决了。
#include
#include
#include
#include
#include
using namespace std; const int N=50010,INF=0x7fffffff; int i,j,k,n,m,T=1; struct heap{ int num,dis; }z[N]; struct edge{ int y,l,z,r; }f[200010*2]; int ans[200010]; int g[N]; void ins(int a,int b,int c){ f[++T].y=b;f[T].l=g[a];g[a]=T;f[T].z=c;f[T].r=i; f[++T].y=a;f[T].l=g[b];g[b]=T;f[T].z=c;f[T].r=i; } int dis[N],v[200010*2],tt=0;//v remark the edge f's k int pos[N];//return the num in heap of point int ret; void up(int k){ int i=k,j; while(i!=1&&i!=-1&&z[i/2].dis>z[i].dis){ z[0]=z[i];z[i]=z[i/2];z[i/2]=z[0]; pos[z[i].num]=i; pos[z[i/2].num]=i/2; i/=2; } } void push(int num,int dis){ z[++tt].num=num; z[tt].dis=dis; pos[num]=tt; up(tt); } int get(){ int re=z[1].num; pos[re]=-1; z[1]=z[tt]; pos[z[tt].num]=1; tt--; int i=1; while(i*2<=tt){ int tem=-1; if(i*2+1>tt||z[i*2].dis
tt||tem==-1)break;else{ z[0]=z[tem];z[tem]=z[i];z[i]=z[0]; pos[z[tem].num]=tem; pos[z[i].num]=i; i=tem; } } return re; } void dij(){ int i,j,k; for(i=1;i<=n-1;i++){ int j=get(); for(k=g[j];k;k=f[k].l){ if(dis[j]+f[k].z
dfn[p]){ ans[++w]=f[k].r; } } } int main(){ cin>>n>>m; for(i=2;i<=n;i++)push(i,INF),dis[i]=INF; for(i=1;i<=m;i++){ int u,v,c; cin>>u>>v>>c; ins(u,v,c); if(v==1){ v=u;u=1; } if(u==1&&z[pos[v]].dis>c){ z[pos[v]].dis=c; up(pos[v]); dis[v]=c; } } dij(); memset(v,0,sizeof(v)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); // for(i=1;i<=n;i++)cout<
<
出行 (Standard IO)
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
【问题の描述】
上海又叫做申城,那里的地铁一直是很拥挤的。鸡腿从张江去邯郸本部的路上常常是挤得……瘦了一圈。但是呢今天因为没有学霸的碾压,鸡腿心情很好决定要出去玩。为了避免遇上残酷的拥挤的地铁线,鸡腿想要查找一些路线中的必经地点,请你来告诉他吧。
上海的地铁被描述为N个点M条边的一个无向图,每次鸡腿会告诉你他在第S条路上,想要到第T条路上(别问我为什么是路上……),你能告诉他有多少个途中的点是他必须要经过的吗?
Input
第一行输入两个正整数N,M表示无向图的点数和边数。
第2到M+1行每行两个整数X、Y,表示X节点和Y节点之间有一条无向边。(数据保证无重边自环)
接下来一行输入一个整数Q,表示有Q个询问
接下来Q行每行两个正整数S、T,表示询问第S条边到第T条边有多少点一定会经过。
Output
对于每个询问输出一行一个整数表示至少有Ans个点一定会经过。
Sample Input
5 6
1 2
1 3
2 3
3 4
4 5
3 5
2
2 3
2 4
Sample Output
0
1
Data Constraint
对于20%的数据1 ≤ N ≤ 10^2,1 ≤ M ≤ 10^3,1 ≤ Q ≤ 10^3;
对于40%的数据 1 ≤ N ≤ 10^3,1 ≤ M ≤ 10^4,1 ≤ Q ≤ 10^3;
对于100%的数据 1 ≤ N ≤ 10^4,1 ≤ M ≤ 10^5,1 ≤ Q ≤ 10^4,0<Xi,Yi ≤ N, 0< S,T ≤ M。
这题他是从边出发到边的。应联想到化边为点。
是人都会想到要用tarjan,我们应找割点,然后呢?
对,化边集为点,将双联通的边集化为一个点,然后割点单独一个点
新图必定是一个边点隔一个割点的一颗数。
那么问题转化成求树上两点距离,这个可以logN实现,用倍增求LCA。
#include
#include
#include
#include
using namespace std;
const int N=200010,M=200010;
int g[N],T,n,m,i,j,k,d[N],indez[31];
struct edge{
int y,l,re;
}f[M*2];
inline void ins(int a, int b,int r){
f[++T].y=b;f[T].l=g[a];g[a]=T;f[T].re=r;
f[++T].y=a;f[T].l=g[b];g[b]=T;f[T].re=r;
}
int dfn[N],low[N],num=0,ti=0,now,stack[M],forst,edgN[M];
int Ng[N];
bool cut[N];
edge Nf[N];
void Nins(int a,int b){
Nf[++T].y=b;Nf[T].l=Ng[a];Ng[a]=T;
Nf[++T].y=a;Nf[T].l=Ng[b];Ng[b]=T;
}
int _n[N] ;
bool v[N+M];
int R_V;
int findd=0;
//edge nf[M*2];
void dfs(int po,int fa){//aimed at Making New Graph && Getting edge into point , marking every point , N_G point needn't mark
int i,j,k;
dfn[po]=low[po]=++ti;
for(k=g[po];k;k=f[k].l){
j=f[k].y;
bool p=(dfn[j]==0);
if(dfn[j]==0){
dfs(j,po);
if(po==1)findd++;
if(low[j]>=dfn[po]&&(po!=1||findd>1)){
cut[po]=1;
R_V=po;
}
}
if(fa!=j&&p)low[po]=min(low[po],low[j]);else
if(fa!=j)low[po]=min(dfn[j],low[po]);
}
}
bool jud[N];
int _d[N],ford;
void _dfs(int po,int fa){
int i,j,k;
dfn[po]=low[po]=++ti;
jud[po]=1;
for(k=g[po];k;k=f[k].l){
j=f[k].y;
bool p=(dfn[j]==0);
if(v[f[k].re]==0){
v[f[k].re]=1;
stack[++forst]=f[k].re;
}
if(jud[j]==0){
_dfs(j,po);
if(low[j]>=dfn[po]&&(po!=1||findd>1)){
if(_n[po]==0)_n[po]=++num;
++num;
while(stack[forst+1]!=f[k].re)edgN[stack[forst--]]=num;
Nins(num,_n[po]);
while(low[_d[ford]]>=dfn[po])Nins(_n[_d[ford--]],num);
}
}
if(fa!=j&&p)low[po]=min(low[po],low[j]);else
if(fa!=j)low[po]=min(dfn[j],low[po]);
}
if(cut[po])_d[++ford]=po;
}
int dep[N+M],l[M+N][63];
int Pre_LCA(int po,int depth,int fa){
v[po]=1;
dep[po]=depth;
l[po][0]=fa;
for(int j=1;j<=30&&indez[j]<=depth-1;j++){
l[po][j]=l[l[po][j-1]][j-1];
}
for(int k=Ng[po];k;k=Nf[k].l){
int j=Nf[k].y;
if(!v[j]){
Pre_LCA(j,depth+1,po);
}
}
}
int LCA(int a,int b){
int sub=abs(dep[a]-dep[b]),x,y;
if(dep[a]>dep[b])x=a,y=b;else x=b,y=a;
int j=0,ret=0;
while(sub){
if(sub%2){
ret+=indez[j];
x=l[x][j];
}
++j;
sub/=2;
}
int lim,i;
for(i=0;i<=30&&indez[i]<=dep[x]-1;i++);
lim=--i;
if(lim<0||x==y)return ret;else{
while(i>=0){
for(i=lim;i>=0;i--){
if(l[x][i]!=l[y][i]){
x=l[x][i],y=l[y][i];
ret+=2*indez[i];
}
}
}
++ret;
x=l[x][0];
++ret;
y=l[y][0];
}
if(x!=y||x<=0||y<=0)return 0;
return ret;
}
int rec[N];
int main(){
indez[0]=1;
for(i=1;i<=30;i++)indez[i]=indez[i-1]*2;
cin>>n>>m;
for(i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
ins(x,y,i);
}
T=0;
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)if(dfn[i]==0)dfs(i,0);
memset(jud,0,sizeof(jud));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
ti=0;
for(i=1;i<=n;i++)if(dfn[i]==0){
_dfs(i,0);
++num;
while(forst)edgN[stack[forst--]]=num;
while(ford)Nins(_n[_d[ford--]],num);
}
memset(v,0,sizeof(v));
for(i=1;i<=num;i++)if(v[i]==0)Pre_LCA(i,1,0);//po depth fa
int Q;
cin>>Q;
while(Q--){
int s,t;
scanf("%d%d",&s,&t);
int ans=LCA(edgN[s],edgN[t])/2;
cout<
<