洛谷P2505||bzoj2750 [HAOI2012]道路 && zkw线段树

时间:2023-11-26 14:47:44

https://www.luogu.org/problemnew/show/P2505

https://www.lydsy.com/JudgeOnline/problem.php?id=2750

神奇的题目...

题解

好像dijkstra序(dijkstra遍历点的顺序)就是“最短路dag”的一个拓扑序

错误记录:127行写成addto(d2[u],dn[v])

然而此题卡常,学了一下zkw线段树优化dijkstra

 #pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
struct pii
{
int fi,se;
pii():fi(),se(){}
pii(int a,int b):fi(a),se(b){}
};
bool operator<(const pii &a,const pii &b)
{
return a.fi<b.fi;
}
namespace SS
{
int M;pii d[];
void init(int n)
{
int i;
//zkw线段树是满二叉树,i的lc为i*2(i<<1),rc为i*2+1(i<<1|1)
for(M=;M<=n+;M<<=);
//M-1表示除叶节点外共有多少节点
//理论上写M<=n就够了,写M<=n+1是为了简化后面边界处理
for(i=M;i<=M+M-;++i) d[i]=pii(0x3f3f3f3f,i-M);
//d[M+0..M+n]存储"数组"a[0..n]即叶节点
//注意叶节点下标从0开始
for(i=M-;i;--i) d[i]=min(d[i<<],d[i<<|]);
}
void set(int p,int x)
{
d[M+p]=pii(x,p);
for(int i=(M+p)>>;i;i>>=)
d[i]=min(d[i<<],d[i<<|]);
}
inline pii qmin()
{
return d[];
}
}
struct E
{
int to,nxt,d;
};
const int md=1e9+;
void addto(int &x,int y)
{
x+=y;
if(x>=md) x-=md;
}
int mul(int x,int y){return ll(x)*y%md;}
int an[];
int n,m;
namespace G
{
E e[];
int f1[],ne;
void me(int x,int y,int z)
{
e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;
}
int d[],dn[],d2[];
int tt[];
bool vis[];
void calc(int S)
{
int u,k,v,i;pii t;
memset(d+,0x3f,sizeof(d[])*n);
memset(dn+,,sizeof(dn[])*n);
memset(vis+,,sizeof(vis[])*n);
memset(d2+,,sizeof(d2[])*n);
tt[]=;
SS::init(n);
SS::set(S,);
d[S]=;dn[S]=;
while()
{
t=SS::qmin();
if(t.fi==0x3f3f3f3f) break;
//printf("at%d %d\n",t.fi,t.se);
u=t.se;SS::set(u,0x3f3f3f3f);
//if(vis[u]) continue;
tt[++tt[]]=u;
vis[u]=;
for(k=f1[u];k;k=e[k].nxt)
{
v=e[k].to;
if(d[v]>d[u]+e[k].d)
{
d[v]=d[u]+e[k].d;
dn[v]=dn[u];
SS::set(v,d[v]);
}
else if(d[v]==d[u]+e[k].d)
addto(dn[v],dn[u]);
}
}
for(i=tt[];i>=;--i)
{
u=tt[i];d2[u]=;
for(k=f1[u];k;k=e[k].nxt)
{
v=e[k].to;
if(d[v]==d[u]+e[k].d)
{
addto(d2[u],d2[v]);
}
}
}
for(i=;i<=tt[];++i)
{
u=tt[i];
for(k=f1[u];k;k=e[k].nxt)
{
v=e[k].to;
if(d[v]==d[u]+e[k].d)
addto(an[k],mul(dn[u],d2[v]));
}
}
}
};
int main()
{
int i,x,y,z;
scanf("%d%d",&n,&m);
for(i=;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&z);
G::me(x,y,z);
}
for(i=;i<=n;++i)
{
G::calc(i);
}
for(i=;i<=m;++i)
printf("%d\n",an[i]);
return ;
}