洛谷P1710 地铁涨价

P1710 地铁涨价

  •  
  • 51通过
  • 339提交
  • 题目提供者洛谷OnlineJudge
  • 标签O2优化云端评测2
  • 难度提高+/省选-

 提交  讨论  题解  

最新讨论

  • 求教:为什么只有40分
  • 数组大小一定要开够啊...
  • 如果强制在线会怎么样
  • 请问为什么第二段铁路变化后…
  • 话说这题和初赛的最后一个大…

题目背景

本题开O2优化,请注意常数

题目描述

博艾市除了有海底高铁连接中国大陆、台湾与日本,市区里也有很成熟的轨道交通系统。我们可以认为博艾地铁系统是一个无向连通图。博艾有N个地铁站,同时有M小段地铁连接两个不同的站。

地铁计价方式很简单。从A站到B站,每经过一小段铁路(连接直接相邻的两个点的一条边),就要收取1博艾元。也就是说,从A站到B站,选择的路径不一样,要价也会不同。

我们认为凡华中学在1号地铁站。学生们通过地铁通勤,他们当然知道选择最短路来坐车的话,票价最便宜。

然而博艾地铁公司经营不善,一直亏损,于是他们打算提价。提价一次就是将一小段铁路原来收费1元改收2元。同一小段的铁路不会多次提价。他们打算提价Q次。

学生们知道,如果他们到学校的一条最短路径中的一小段提价了,可以改变路径,使总票价不变。然而随着一条一条的铁路被提价,当居住在某个站附近的学生发现,提价后,没有任何一种方案可以从家到学校的费用和初始费用相等时,就会不满。

现在地铁公司希望知道,对于每一次涨价,有多少个站,学生会因为涨价而不满呢?

输入输出格式

输入格式:

第一行为三个整数N,M,Q。

接下来M行,每行2个整数ai,bi,表示第i条铁路连接的两个站。i表示铁路编号。

接下来Q行,每行一行整数rj,表示每次涨价的铁路编号。

输出格式:

Q行。每行一个整数表示不满的车站数量。

输入输出样例

输入样例#1

5 6 5

1 2

1 3

4 2

3 2

2 5

5 3

5

2

4

1

3

输出样例#1

0

2

2

4

4

说明

【样例解释】

次数 车站2 车站3 车站4 车站5

初始 1     1     2     2

1    1     1     2     2

2    1     2     2     3

3    1     2     2     3

4    2     2     3     3

5    2     2     4     3

【数据范围】

对于20%的数据 N≤100, Q≤30

对于40%的数据 Q≤30

对于70%的数据 正确的输出结果中,不会有超过50种不一样的整数(数据范围剧透解法系列)

对于100%的数据 N≤100000, Q≤M≤200000

分析:难度比较大的一题,如果先求出最短路,然后删边再求一次最短路能得40分,必须要提高效率.首先,删的边只有在从1到每个点的最短路上才有用,我们可以用bfs求出最短路图,即1到每个点的最短路的图,判断一条边删掉之后有多少个点的最短路会变,那么从1到这个点的最短路数量一定多于1,会发现并不好记录到每个点的最短路数量,那么我们可以把原本的无向图变成一个DAG,即求最短路图的时候只连一条边,我们在求出最短路图的时候顺便记录下每个点的父亲数,这样的话能判断最短路的数量.

然后开始删边,这里不能单单只删两个点,可能两个点都被记录了但不是同一条边,正确的做法是记录边。如果删的这条边是最短路图上的边,那么从这条边指向的点开始dfs,如果这个点的父亲数-1后恰好等于0,那么1到这个点的最短路被改变了,从这个点开始继续dfs,标记被删边影响到的点.

当然,可以考虑离线做法,即将删边变成加边,不过dfs的意义和删边恰好相反,知道可以这么做即可。

不过本题的数据非常诡异,数组的大小要非常小心的确定,不然就会70分.

70分加边代码:

 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int maxn = 400010;

int n, m, q,cnt = 1,d1[maxn],ans[maxn],qq[maxn],pd[maxn],vis[maxn],flag[maxn],viss[maxn];
int head[maxn], to[maxn], nextt[maxn], tot1 = 1;
int head1[maxn], to1[maxn], nextt1[maxn], tot2;

struct node
{
    int x, y;
}e[maxn];

void add(int x, int y)
{
    tot1++;
    to[tot1] = y;
    nextt[tot1] = head[x];
    head[x] = tot1;
}

void add2(int x, int y)
{
    tot2++;
    to1[tot2] = y;
    nextt1[tot2] = head1[x];
    head1[x] = tot2;
}

void bfs1()
{
    queue <int> q;
    viss[1] = 1;
    q.push(1);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (!viss[v])
            {
                d1[v] = d1[u] + 1;
                q.push(v);
                viss[v] = 1;
            }
        }
    }
}

void bfs2()
{
    memset(viss, 0, sizeof(viss));
    queue <int> q;
    viss[1] = 1;
    q.push(1);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (d1[v] == d1[u] + 1)
                flag[i / 2] = 1;
            if (!viss[v])
            {
                viss[v] = 1;
                q.push(v);
            }
        }
    }
}

void dfs(int u)
{
    cnt++;
    vis[u] = 1;
    for (int i = head1[u]; i; i = nextt1[i])
    {
        int v = to1[i];
        if (!vis[v])
            dfs(v);
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= m; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        e[i].x = a, e[i].y = b;
        add(a, b);
        add(b, a);
    }
    bfs1();
    bfs2();
    
    for (int i = 1; i <= q; i++)
    {
        int a;
        scanf("%d", &a);
        pd[a] = 1;
        qq[i] = a;
    }
    for (int i = 1; i <= m; i++)
        if (d1[e[i].x] > d1[e[i].y])
            swap(e[i].x, e[i].y);
    vis[1] = 1,cnt = 1;
    for (int i = 1; i <= m; i++)
        if (!pd[i] && flag[i])
        {
        if (vis[e[i].x] && vis[e[i].y])
            continue;
        add2(e[i].x, e[i].y);
        if (vis[e[i].x])
            dfs(e[i].y);
        }
    ans[q] = n - cnt;
    for (int i = q - 1; i; i--)
    {
        int temp = qq[i + 1];
        //if (e[temp].x && e[temp].y)
            //continue;
        if (!(vis[e[temp].x] && vis[e[temp].y]) && flag[temp])
            add2(e[i].x, e[i].y);
        if (vis[e[temp].x] && flag[temp] && !vis[e[temp].y])
            dfs(e[temp].y);
        ans[i] = n - cnt;
    }
    for (int i = 1; i <= q; i++)
        printf("%d\n", ans[i]);
        
    //while (1);

    return 0;
}

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;

struct Edge {
    int u, v;
} edge[800010];

int n, m, q, B, ans = 0;
vector<int> aG[200010];
vector<int> G[200010];
int fa[200010];
int query[200010];
queue<int> Q;
int d[400010];
int r_u[400010], r_v[400010];
bool vis[400010];
bool cnt[700010];

inline int min(int x, int y) { return x > y ? y : x; }
inline int max(int x, int y) { return x < y ? y : x; }

inline void addedge2(int a, int b) {
    edge[B].u = a, edge[B].v = b;
    aG[a].push_back(B++);
}

inline void addedge(int a, int b) {
    edge[B].u = a, edge[B].v = b;
    fa[b] ++;
    G[a].push_back(B++);
}

inline void in() {
    int i, a, b, c;
    scanf("%d%d%d", &n, &m, &q);
    for (i = 1; i <= m; i++) {
        scanf("%d%d", &a, &b);
        addedge2(a, b);
        addedge2(b, a);
        r_u[i] = a, r_v[i] = b;
    }
    for (i = 0; i < q; i++) scanf("%d", query + i);
}

inline void BFS() {
    int sz, x, i;
    memset(d, 0x3f, sizeof(d));
    vis[1] = 1, d[1] = 0, Q.push(1);
    while (!Q.empty()) {
        x = Q.front(); Q.pop();
        sz = aG[x].size();
        for (i = 0; i < sz; i++) {
            Edge& e = edge[aG[x][i]];
            if (d[e.v] == d[x] + 1) addedge(x, e.v);
            if (!vis[e.v]) {
                d[e.v] = d[x] + 1, addedge(x, e.v);
                vis[e.v] = 1;
                Q.push(e.v);
            }
        }
    }
}

inline void _del(int x) {
    cnt[x] = 1;
    int i, u = edge[x].u, v = edge[x].v;
    fa[v] --;
    if (fa[v] >= 1 || fa[v] < 0) return;
    ans++;
    //cout << v <<' '<<fa[v] << endl;
    int sz = G[v].size();
    for (i = 0; i < sz; i++) {
        Edge& e = edge[G[v][i]];
        if (!cnt[G[v][i]] && d[e.v] == d[v] + 1) _del(G[v][i]);
    }
}

//建最短路DAG,然后删边时看看儿子的所有父亲能不能连过来,能的话就不变,不能的话说明儿子不是最短路了,需要切除其所有出边,重复刚刚的过程

inline void solve() {
    int i, j;
    BFS();
    for (i = 1; i <= m; i++) {
        if (d[r_u[i]] > d[r_v[i]]) swap(r_u[i], r_v[i]);
    }
    for (i = 0; i < q; i++) {
        int sz = G[r_u[query[i]]].size();
        for (j = 0; j < sz; j++) {
            Edge& e = edge[G[r_u[query[i]]][j]];
            if (e.v == r_v[query[i]]) {
                if (!cnt[G[r_u[query[i]]][j]])
                    _del(G[r_u[query[i]]][j]);
                break;
            }
        }
        printf("%d\n", ans);
    }
}

int main() {
    in();
    solve();
    return 0;
}

 

 

posted @ 2016-11-03 20:04  zbtrs  阅读(240)  评论(0编辑  收藏  举报