• luogu P1710 地铁涨价


    嘟嘟嘟

    一道最短路好题。

    首先明确一点,把一条边的边权变成2,等于删去这条边。因为变成2后最短路肯定不会经过这条边,就相当于删去这条边了。

    所以题目变成了依次删去Q条边,求每一次删完边后有几个点的最短路变大了。

    多做做题就会有这么个思维:删边不好办,然而逆向加边方便多了。所以30做法就是离线逆向加边,跑Q次dijkstra。时间复杂度(Qnlogn)。

    正解是基于这个暴力的:想想dijkstra更新最短路的时候,如果成功从u更新了dis[v],那么前提一定是dis[u]已经是最短路。所以每一次我们可以不跑dijkstra,只用判断加的边(x, y)中,当前距离dis2[x]或是dis2[y]是否已经成为了最短路,如果是,就从这个点开始尝试更新他能走到的点的最短路(bfs, dfs都行,实测dfs更快)。然后如果到一个点的距离变成了最短路,ans--。

    然后就是代码细节了:因为Q <= m,所以有一些边没删去,所以事先要加上,加边的时候不要每一次都判断dis2[x]或dis2[y]是否成为了最短路,而是在循环外面直接从1号节点更新,因为只有1号结点延伸出去的才可能成为最短路。而要是每一都判断dfs的话,虽然dfs会马上退出来,然而如果是一个菊花图的话,对于1号结点,每一次都遍历了很多条边,时间复杂度达到O(n2)。(这也就是我第7个点为啥一直TLE的原因……)

    还有就是dis2实际上用一个bool数组就够,标记过就表示这个点已经成为了最短路,不用记录他的距离。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 1e5 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 
     37 int n, m, q;
     38 struct Edge
     39 {
     40     int nxt, to;
     41 }e[maxn << 2];
     42 int head[maxn], ecnt;
     43 void add(int x, int y)
     44 {
     45     e[++ecnt] = (Edge){head[x], y};
     46     head[x] = ecnt;
     47 }
     48 
     49 struct Node
     50 {
     51     int x, y;
     52 }egs[maxn << 1];
     53 
     54 #define pr pair<int, int>
     55 #define mp make_pair
     56 bool in[maxn];
     57 int dis[maxn];
     58 void dijkstra(int s)
     59 {
     60     Mem(dis, 0x3f);
     61     dis[s] = 0;
     62     priority_queue<pr, vector<pr>, greater<pr> > q;
     63     q.push(mp(dis[s], s));
     64     while(!q.empty())
     65     {
     66         int now = q.top().second; q.pop();
     67         if(in[now]) continue;
     68         in[now] = 1;
     69         for(int i = head[now]; i != -1; i = e[i].nxt)
     70         {
     71             if(dis[e[i].to] > dis[now] + 1)
     72             {
     73                 dis[e[i].to] = dis[now] + 1;
     74                 q.push(mp(dis[e[i].to], e[i].to));
     75             }
     76         }
     77     }
     78 }
     79 
     80 bool vis[maxn << 1];
     81 int a[maxn << 1], ans[maxn << 1], num;
     82 
     83 void solve(int now, int d)
     84 {
     85     for(int i = head[now]; i != -1; i = e[i].nxt)
     86     {
     87         if(!vis[e[i].to] && d + 1 == dis[e[i].to])
     88         {
     89             num--;
     90             vis[e[i].to] = 1;
     91             solve(e[i].to, d + 1);
     92         }
     93     }
     94 }
     95 
     96 int main()
     97 {
     98     Mem(head, -1); ecnt = -1;
     99     n = read(); m = read(); q = read();
    100     for(rg int i = 1; i <= m; ++i)
    101     {
    102         egs[i].x = read(); egs[i].y = read();
    103         add(egs[i].x, egs[i].y); add(egs[i].y, egs[i].x);
    104     }
    105     dijkstra(1);
    106     for(rg int i = 1; i <= q; ++i) a[i] = read(), vis[a[i]] = 1;
    107     Mem(head, -1); ecnt = -1;
    108     num = n - 1;
    109     for(int i = 1; i <= m; ++i) if(!vis[i])
    110     {
    111         int x = egs[i].x, y = egs[i].y;
    112         add(x, y); add(y, x);
    113     }
    114     Mem(vis, 0); vis[1] = 1;
    115     solve(1, 0);
    116     for(rg int i = q; i; --i)
    117     {
    118         ans[i] = num;
    119         int x = egs[a[i]].x, y = egs[a[i]].y;
    120         add(x, y); add(y, x);
    121         if(vis[x]) solve(x, dis[x]);
    122         if(vis[y]) solve(y, dis[y]);        
    123     }
    124     for(rg int i = 1; i <= q; ++i) write(ans[i]), enter;
    125     return 0;
    126 }
    View Code
  • 相关阅读:
    50
    49
    Windows编程之connect函数研究
    48
    C++创建窗口程序初步
    47
    46
    45
    计算机组成原理实验思路
    44(function pointer 2)
  • 原文地址:https://www.cnblogs.com/mrclr/p/9847670.html
Copyright © 2020-2023  润新知