【题解】Atcoder ARC#90 E-Avoiding Collision

2021-07-08 19:04

阅读:614

标签:char   拓扑   for   距离   name   space   front   mes   bool   

  自己做出来固然开心,但是越发感觉到自己写题的确是很慢很慢了……往往有很多的细节反反复复的考虑才能确定,还要加油呀~

  这道题目的突破口在于正难则反。直接求有多少不相交的不好求,我们转而求出所有相交的。我们先预处理出由 \(S\) 到 \(T\) 的最短路图(跑一边Dijkstra,所有的最短路径构成的图),显然可以顺便处理出 \(T\) 到 \(S\) 的。然后这个图是一个拓扑图,满足的性质就是从 \(S\) 点出发的任意一条路径终点均为 \(T\) 且为二者之间的最短路。拓扑图dp对于每个点我们又可以获得  \(Way1[u],  Way2[u]\) 分别表示从起点到 \(u\) 点的总路径数和从终点到 \(u\) 的总路径数。

  之后我们可以分类讨论一下,两条路径相遇是相遇在点上还是相遇在边上。相遇在点上很好判断,就是从起点到 \(u\) 点的距离正好等于从 \(u\) 点到终点的距离;相遇在边上则要求路径的终点落在这条边上,也是可以 O(1) 判断的。这样就好啦~(?´?`?)

#include using namespace std;
#define maxn 500000
#define mod 1000000007
#define int long long
int n, m, dis1[maxn], dis2[maxn];
int ans, K, S, T, Way1[maxn], Way2[maxn];
bool vis[maxn];

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    while(c ‘0 || c > 9) { if(c == -) k = -1; c = getchar(); }
    while(c >= 0 && c ‘9) x = x * 10 + c - 0, c = getchar();
    return x * k;
}

struct edge
{
    int cnp, fr[maxn], to[maxn], co[maxn];
    int last[maxn], head[maxn], degree[maxn];
    edge() { cnp = 2; }
    void add(int u, int v, int w = 0)
    { 
        fr[cnp] = u, to[cnp] = v, co[cnp] = w;
        last[cnp] = head[u], head[u] = cnp ++; 
    }
}E[2], G;

struct node
{
    int x, y;
    node(int _x = 0, int _y = 0) { x = _x, y = _y; }
    friend bool operator const node& a, const node& b)
    { return a.y > b.y; }
}; priority_queue  q;

void Up(int &x, int y) { x = (x + y) % mod; }
int Qpow(int x) { return x * x % mod; }
void Dijk(int S, int *dis)
{
    memset(vis, 0, sizeof(vis));
    dis[S] = 0; q.push(node(S, 0));
    while(!q.empty())
    {
        node now = q.top(); q.pop();
        int u = now.x; if(vis[u]) continue; vis[u] = 1;
        for(int i = G.head[u]; i; i = G.last[i])
        {
            int v = G.to[i];
            if(dis[v] > dis[u] + G.co[i])
            {
                dis[v] = dis[u] + G.co[i];
                q.push(node(v, dis[v]));
            }
        }
    }
}

void Toposort()
{
    memset(vis, 0, sizeof(vis));
    queue int> q; q.push(S);
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = G.head[u]; i; i = G.last[i])
        {
            int v = G.to[i];
            if((dis1[u] + dis2[v] + G.co[i]) == K)
            {
                E[0].add(u, v); E[0].degree[v] ++;
                E[1].add(v, u); E[1].degree[u] ++;
                if(!vis[v]) q.push(v), vis[v] = 1;
            }
        }
    }
}

void TopoDP(int opt, int *Way)
{
    queue int> q;
    for(int i = 1; i ) 
        if(!E[opt].degree[i]) 
            q.push(i), Way[i] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop(); 
        for(int i = E[opt].head[u]; i; i = E[opt].last[i])
        {
            int v = E[opt].to[i];
            E[opt].degree[v] --; Up(Way[v], Way[u]);
            if(!E[opt].degree[v]) q.push(v);
        }
    }
}

signed main()
{
    n = read(), m = read(); S = read(), T = read();
    for(int i = 1; i ) 
    {
        int x = read(), y = read(), w = read();
        G.add(x, y, w), G.add(y, x, w);
    }
    memset(dis1, 127, sizeof(dis1)); memset(dis2, 127, sizeof(dis2)); 
    Dijk(S, dis1), Dijk(T, dis2);
    K = dis1[T]; Toposort(); 
    TopoDP(0, Way1); TopoDP(1, Way2);
    for(int i = 1; i )
        if(dis1[i] + dis1[i] == K) 
            Up(ans, Qpow(Way1[i] * Way2[i] % mod) % mod);
    for(int i = 2; i 1].cnp; i ++)
    {
        int u = E[0].fr[i], v = E[0].to[i];
        if(dis1[u] * 2 == K || dis1[v] * 2 == K) continue;
        if(K > 2 * dis1[u] && K 2 * (K - dis2[v])) 
            Up(ans, Qpow(Way1[u] * Way2[v] % mod) % mod);
    }
    ans = (Way1[T] * Way1[T] % mod - ans + mod) % mod;
    printf("%lld\n", ans);
    return 0;
}

 

【题解】Atcoder ARC#90 E-Avoiding Collision

标签:char   拓扑   for   距离   name   space   front   mes   bool   

原文地址:https://www.cnblogs.com/twilight-sx/p/9733849.html


评论


亲,登录后才可以留言!