题面
Sol
先正反两遍 Dijsktra D i j s k t r a 算出经过某个点的 S S 到的最短路条数 F F
满足条件一就是要满足
条件二
标算比较简单
直接 bitset b i t s e t 存储不能到达它的和它不能到的点
然后开 map m a p 把所有相同的 F(B) F ( B ) 变成 bitset b i t s e t
然后每次枚举 A A ,就直接查表然后用里的 count c o u n t 就好了
注意如果 ST S T 不连通输出 C2n C n 2
空间 1GB 1 G B 就可以过
注意!!!
AC A C 的同志不要以为真的 AC A C 了!!!
数据真的水
S S 到的路径条数不会大于 1 1
然后我自己乱打一个,样例都没过就了
标算代码
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(50005);
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, m, cnt, S, T, first[_], d[_], vis[_];
struct Edge{
int to, next, w;
} edge[_ << 1];
ll dis[2][_], f[2][_], F[_], ans;
struct Point{
int u; ll d;
IL int operator <(RG Point B) const{
return d > B.d;
}
};
priority_queue <Point> Q;
queue <int> Que;
bitset <50000> G[2][_];
map <ll, bitset <50000> > M;
IL void Add_Graph(RG int u, RG int v, RG int w){
edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
}
IL void Dijkstra(RG int op){
for(RG int i = 1; i <= n; ++i) dis[op][i] = (ll)1e18, vis[i] = 0;
if(!op) f[op][S] = 1, dis[op][S] = 0, Q.push((Point){S, 0});
else f[op][T] = 1, dis[op][T] = 0, Q.push((Point){T, 0});
while(!Q.empty()){
RG Point x = Q.top(); Q.pop();
if(vis[x.u]) continue;
vis[x.u] = 1;
for(RG int e = first[x.u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(x.d + w < dis[op][v]){
dis[op][v] = x.d + w, f[op][v] = f[op][x.u];
Q.push((Point){v, x.d + w});
}
else if(x.d + w == dis[op][v]) f[op][v] += f[op][x.u];
}
}
}
IL int Check(RG int x, RG ll w, RG int y, RG int op){
return dis[op][x] + w + dis[!op][y] == dis[0][T];
}
IL void TopSort(RG int op){
for(RG int i = 1; i <= n; ++i)
for(RG int e = first[i]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(Check(i, w, v, op)) ++d[v];
}
for(RG int i = 1; i <= n; ++i) if(!d[i]) Que.push(i);
while(!Que.empty()){
RG int u = Que.front(); Que.pop();
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(!Check(u, w, v, op)) continue;
G[op][v] &= G[op][u];
if(!--d[v]) Que.push(v);
}
}
}
int main(RG int argc, RG char* argv[]){
Fill(first, -1), n = Input(), m = Input(), S = Input(), T = Input();
for(RG int i = 1; i <= m; ++i){
RG int u = Input(), v = Input(), w = Input();
Add_Graph(u, v, w), Add_Graph(v, u, w);
}
Dijkstra(0);
if(!f[0][T]) return printf("%lld\n", 1LL * n * (n - 1) >> 1), 0;
Dijkstra(1);
for(RG int i = 1; i <= n; ++i){
G[0][i].set(), G[1][i].set();
G[0][i][0] = G[0][i][i] = G[1][i][0] = G[1][i][i] = 0;
}
TopSort(0), TopSort(1);
for(RG int i = 1; i <= n; ++i)
if(dis[0][i] + dis[1][i] == dis[0][T]) F[i] = f[0][i] * f[1][i];
for(RG int i = 1; i <= n; ++i) M[F[i]].set(i);
for(RG int i = 1; i <= n; ++i)
ans += (M[F[T] - F[i]] & G[0][i] & G[1][i]).count();
return printf("%lld\n", ans >> 1), 0;
}
然而Bzoj的空间变成了512MB
TAT
然后还可以这样做
首先可以枚举一条最短路上的点 i i
然后枚举不在这条最短路上的点再来统计答案
把最短路弄出来到一个数组中
然后不在这条路上的点的合法的是这个数组的下标的区间 [l,r] [ l , r ]
然后可以正反两边拓扑排序求出这个区间
为什么是一个区间
首先前提是这个点走到 j j ,然后到 T T 是最短路
如果能走到这个点,那么 j j 的所有前驱都能到这个点
如果这个点能走到,那么这个点也能走到 j j 的所有后继
然后枚举最短路上的点,每次到时,就把左端点是 i i 的加进
然后把右端点是 i i 的从中减掉
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(50005);
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, m, cnt, S, T, first[_], d[_], vis[_], l[_], r[_], p[_], len, pre[_];
struct Edge{
int to, next, w;
} edge[_ << 1];
ll dis[2][_], f[2][_], F[_], ans;
struct Point{
int u; ll d;
IL int operator <(RG Point B) const{
return d > B.d;
}
};
queue <int> Que;
map <ll, int> M;
priority_queue <Point> Q;
vector <int> al[_], ar[_];
IL void Add_Graph(RG int u, RG int v, RG int w){
edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
}
IL void Dijkstra(RG int op){
for(RG int i = 1; i <= n; ++i) dis[op][i] = (ll)1e18, vis[i] = 0;
if(!op) f[op][S] = 1, dis[op][S] = 0, Q.push((Point){S, 0});
else f[op][T] = 1, dis[op][T] = 0, Q.push((Point){T, 0});
while(!Q.empty()){
RG Point x = Q.top(); Q.pop();
if(vis[x.u]) continue;
vis[x.u] = 1;
for(RG int e = first[x.u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(x.d + w < dis[op][v]){
dis[op][v] = x.d + w, f[op][v] = f[op][x.u];
Q.push((Point){v, x.d + w});
if(op) pre[v] = x.u;
}
else if(x.d + w == dis[op][v]) f[op][v] += f[op][x.u];
}
}
}
IL int Check(RG int x, RG ll w, RG int y, RG int op){
return dis[op][x] + w + dis[!op][y] == dis[0][T];
}
IL void TopSort(RG int op){
for(RG int i = 1; i <= n; ++i)
for(RG int e = first[i]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(Check(i, w, v, op)) ++d[v];
}
for(RG int i = 1; i <= n; ++i) if(!d[i]) Que.push(i);
while(!Que.empty()){
RG int u = Que.front(); Que.pop();
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(!Check(u, w, v, op)) continue;
op ? r[v] = min(r[v], r[u]) : l[v] = max(l[v], l[u]);
if(!--d[v]) Que.push(v);
}
}
}
int main(RG int argc, RG char* argv[]){
Fill(first, -1), n = Input(), m = Input(), S = Input(), T = Input();
for(RG int i = 1; i <= m; ++i){
RG int u = Input(), v = Input(), w = Input();
Add_Graph(u, v, w), Add_Graph(v, u, w);
}
Dijkstra(0);
if(!f[0][T]) return printf("%lld\n", 1LL * n * (n - 1) >> 1), 0;
Dijkstra(1);
for(RG int i = S; i; i = pre[i]) p[++len] = i, l[i] = len + 1, r[i] = len - 1;
for(RG int i = 1; i <= n; ++i) if(!(l[i] + r[i])) l[i] = 1, r[i] = len;
TopSort(0), TopSort(1);
for(RG int i = 1; i <= n; ++i){
if(dis[0][i] + dis[1][i] == dis[0][T]) F[i] = f[0][i] * f[1][i];
if(l[i] > r[i]) continue;
al[l[i]].push_back(i), ar[r[i]].push_back(i);
}
for(RG int i = 1; i <= len; ++i){
for(RG int l = al[i].size(), j = 0; j < l; ++j) ++M[F[al[i][j]]];
ans += M[F[T] - F[p[i]]];
for(RG int l = ar[i].size(), j = 0; j < l; ++j) --M[F[ar[i][j]]];
}
return printf("%lld\n", ans), 0;
}