T4 路径
【问题描述】
Y Y Y有一个 n n n 个点, m m m 条边的无向图,规定起点 S S S 和终点 T T T(保证 S / T S/T S/T 联通),一个人从 S S S 到 T T T 的任意一条最短路都算一条关键路径,而关键路径上的点被称作关键点。假设每个单位 时间能够移动 1 的长度,你需要完成一下任务:对于第 i i i 个点,如果其不是关键点,请输出 “ 0 0 0”;如果是关键点,设从 S S S 走最短路到点 i i i 的时刻为 T i T_i Ti( 0 0 0 时刻从 S S S 出发),输出在时间为 T i T_i Ti 时,这个人走关键路径可以到达的不同位置的数量。(注:这个人不一定在节点上,可能 在边上,比如一条长度为 7 7 7 的边,他可以在长度为 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 1,2,3,4,5,6 的地方,而不仅限于两个端点)。 你轻易地就解决了这道题。
【输入格式】
第一行为用空格隔开的三个正整数 n , S , T n,S,T n,S,T。
第二行为一个正整数 m m m。 接下来 m m m 行每行三个正整数 x , y , z , x,y,z, x,y,z,表示 x x x 和 y y y 之间有一条长度为 z z z 的无向边。
【输出格式】
输出共 n n n 行。
第 i i i 行请输出对应第 i i i 个点所应输出信息。
【输入样例】
4 1 4
4
1 2 3
1 3 4
2 4 4
3 4 3
【输出样例】
1
2
2
1
【数据范围】
对于前 20%的数据,$n ≤ 10 $
对于另外 20%的数据,保证是一棵树
对于 100%的数据, n ≤ 2000 , m ≤ 2 ∗ 1 0 5 , z ≤ 106 n ≤ 2000,m ≤ 2*10^5,z ≤ 106 n≤2000,m≤2∗105,z≤106
【题解】
先跑出最短路,对于在关键路上的边的两个端点
u
,
v
u,v
u,v
(
d
i
s
t
[
u
]
<
d
i
s
t
[
v
]
)
(dist[u]<dist[v])
(dist[u]<dist[v]),可以直接把
d
i
s
t
[
u
]
−
>
d
i
s
t
[
v
]
dist[u]->dist[v]
dist[u]−>dist[v]区间中的答案都加一。输出第
i
i
i个点的答案时,直接输出
d
i
s
t
[
i
]
dist[i]
dist[i]所对应的答案。
要说图论这题放T4其实还好,虽然当时我没有打出来(真是
f
w
fw
fw)
不想再自己敲了,下面是标程。我觉得
h
a
s
h
hash
hash可以用
p
b
d
s
pbds
pbds里的,还有
s
p
f
a
spfa
spfa不如
d
i
j
k
s
t
r
a
dijkstra
dijkstra。
#include<bits/stdc++.h>
using namespace std;
const int Mod=131071;
int N,S,T;
int M;
int dist[2010]={0};
int st=1,en=0;
int num=0;
int HASH[2010]={0};
int dui[131100]={0};
int D[2010]={0};
int Sum[2010]={0};
int Sp=0;
struct bian_{
int st;
int to;
int next;
int dis;
}bian[400010]={{0,0,0,0}};
int First[2010]={0};
int vis[2010]={0};
void Add(int p,int q,int r,int k){
bian[k].next=First[p];
bian[k].st=p;
bian[k].to=q;
bian[k].dis=r;
First[p]=k;
return;
}
void SPFA(){
memset(dist,0x3f3f3f3f,sizeof(dist));
dui[++en]=S;
dist[S]=0;
num=1;
for(;num>0;){
int u=dui[st];
st=(st&Mod)+1;
HASH[u]=0;num--;
for(int i=First[u];i!=0;i=bian[i].next){
int v=bian[i].to;
if(dist[v]>dist[u]+bian[i].dis){
dist[v]=dist[u]+bian[i].dis;
if(HASH[v]==0){
HASH[v]=1;
if(dist[v]<dist[dui[st]]){
st=((st+Mod-1)&Mod)+1;
dui[st]=v;
}
else{
en=(en&Mod)+1;
dui[en]=v;
}
num++;
}
}
}
}
return;
}
int Find(int k){
for(int l=1,r=Sp;l<=r;){
int mid=(l+r)>>1;
if(D[mid]==k) return mid;
if(D[mid]<k) l=mid+1;
else r=mid-1;
}
return 0;
}
int main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d%d%d",&N,&S,&T);
scanf("%d",&M);
for(int i=1;i<=M;i++){
int p,q,r;
scanf("%d%d%d",&p,&q,&r);
Add(p,q,r,(i<<1)-1);
Add(q,p,r,i<<1);
}
SPFA();
for(int i=1;i<=N;i++)
D[++Sp]=dist[i];
sort(D+1,D+N+1);
Sp=1;
for(int i=2;i<=N;i++)
if(D[i]!=D[i-1])
D[++Sp]=D[i];
for(int i=Sp+1;i<=N;i++) D[i]=0;
en=1;
dui[1]=T;
for(int i=1;i<=en;i++){
int u=dui[i];
for(int p=First[u];p!=0;p=bian[p].next){
int v=bian[p].to;
if(dist[u]==dist[v]+bian[p].dis){
int L=Find(dist[v]),R=Find(dist[u]);
vis[v]=vis[u]=1;
Sum[L+1]++,Sum[R]--;
if(HASH[v]==0)
dui[++en]=v,HASH[v]=1;
}
}
}
for(int i=1;i<=Sp;i++)
Sum[i]+=Sum[i-1];
for(int i=1;i<=N;i++)
if(vis[i]==1)
Sum[Find(dist[i])]++;
for(int i=1;i<=N;i++){
int p=Find(dist[i]);
printf("%d\n",Sum[p]*vis[i]);
}
fclose(stdin);
fclose(stdout);
return 0;
}
看完请留下你的痕迹 t h x thx thx