Kisu Pari Na 2

来源:互联网 发布:淘宝公益是怎么收费 编辑:程序博客网 时间:2024/04/30 09:13

题目描述:

N, M (1 ≤ N ≤ 10000, 0 ≤ M < N).n个点,m条边.给出一个森林,q (1 ≤ q ≤ 10000)次查询,每次给出一个数x.问:一个人顺便走,一共走过x个不同的(包括起点)点所花费的最少的路径长度.树上的边是无向的,权值为1的.

题解:

不联通的树肯定不用放在一起考虑.看一棵树中,怎么走才能够走最近的路.不是简单路径,用树形dp的话可以描述,但是空间和时间都开不下.现在想直径的性质.我们把直径这条链拉出来,如果直径已经够了,就够了x-1的花费.直径不够的话,肯定往两边走,每多一个就是2的代价.这样贪心的走.
这样我们的解法是:一棵树有直径的长度k,和点的个数num.按照num排序,先保证能走x个点.再用树状数快速得到满足num的要求的点中最大的k的值,然后算一下就好了.

重点:

代码:

#include <cstdio>#include <algorithm>#include <vector>#include <cstring>#include <queue>using namespace std;int n, m, Q, x, y, maxd[10010], tot;int vis[10010], deep[10010];struct node {    int num, d;    node (int _num = 0, int _d = 0) {        num = _num;        d = _d;    }    friend bool operator < (node x, node y) {        return x.num < y.num;    } }p[10010];vector <int> gra[10010];queue<int> q;using namespace std;int main() {    int T;    scanf("%d", &T);    for (int cas = 1; cas <= T; ++cas) {        scanf("%d%d", &n, &m);        for (int i = 1; i <= n; ++i) {            gra[i].clear();        }        for (int i = 0; i < m; ++i) {            scanf("%d%d", &x, &y);            gra[x].push_back(y);            gra[y].push_back(x);        }        memset(vis, 0, sizeof vis);        memset(deep, 0, sizeof deep);        tot = 0;        for (int start = 1; start <= n; ++start) {            if (vis[start]) {                continue;            }            q.push(start);            vis[start] = 1;            while (!q.empty()) {                x = q.front();                q.pop();                for (int i = 0; i < gra[x].size(); ++i) {                    if (!vis[gra[x][i]]) {                        vis[gra[x][i]] = 1;                        q.push(gra[x][i]);                    }                }            }            vis[x] = 2;            q.push(x);            p[tot].num = 0;            deep[x] = 0;            while (!q.empty()) {                x = q.front();                q.pop();                p[tot].num++;                for (int i = 0; i < gra[x].size(); ++i) {                    if (vis[gra[x][i]] < 2) {                        vis[gra[x][i]] = 2;                        deep[gra[x][i]] = deep[x] + 1;                        q.push(gra[x][i]);                    }                }            }            p[tot].d = deep[x];            tot++;        }        sort(p, p + tot);        maxd[tot] = 0;        for (int i = tot - 1; i >= 0; --i) {            maxd[i] = p[i].d;            maxd[i] = max(maxd[i], maxd[i + 1]);        }        scanf("%d", &Q);        printf("Case %d:\n", cas);        while (Q--) {            scanf("%d", &x);            int pos = lower_bound(p, p + tot, node(x, 0)) - p;            if (pos == tot) {                printf("impossible\n");            }            else {                if (maxd[pos] >= x - 1) {                    printf("%d\n", x - 1);                }                else {                    printf("%d\n", (x - maxd[pos] - 1) * 2 + maxd[pos]);                }            }        }    }    return 0;}
0 0