「2018泉州国庆集训#5」 – 解题报告

A – 找位置

首先发现\(k\)非常的小,且\(n\)也较小,所以考虑直接暴力,枚举经过每一个超市的顺序,然后顺起来就行了(提前处理\(k\)次最短路即可)。

// A.cpp
#include <bits/stdc++.h>
#define pr pair<int, int>

using namespace std;

const int MAX_N = 1e4 + 200, MAX_E = 2e5 + 200, MAX_K = 6;

int head[MAX_N], current, n, m, k, *dist, distances[MAX_K][MAX_N], k_set[MAX_K], dist_id[MAX_N];
bool vis[MAX_N];

struct edge
{
    int to, nxt, weight;
} edges[MAX_E << 1];

void addpath(int src, int dst, int weight)
{
    edges[current].to = dst, edges[current].weight = weight;
    edges[current].nxt = head[src], head[src] = current++;
}

void shortest_path(int st)
{
    memset(dist, 0x3f, sizeof(distances[0]));
    memset(vis, false, sizeof(vis));
    priority_queue<pr> pq;
    dist[st] = 0, pq.push(make_pair(0, st));
    while (!pq.empty())
    {
        int u = pq.top().second;
        pq.pop();
        if (vis[u])
            continue;
        vis[u] = true;
        for (int i = head[u]; i != -1; i = edges[i].nxt)
            if (dist[edges[i].to] > dist[u] + edges[i].weight)
                dist[edges[i].to] = dist[u] + edges[i].weight, pq.push(make_pair(-dist[edges[i].to], edges[i].to));
    }
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= k; i++)
        scanf("%d", &k_set[i]), dist_id[k_set[i]] = i;
    for (int i = 1, u, v, w; i <= m; i++)
        scanf("%d%d%d", &u, &v, &w), addpath(u, v, w), addpath(v, u, w);
    for (int i = 1; i <= k; i++)
        dist = distances[i], shortest_path(k_set[i]);
    int gans = 0x3f3f3f3f;
    do
    {
        // insert it;
        int pans = 0;
        for (int i = 1; i < k; i++)
            pans += distances[dist_id[k_set[i]]][k_set[i + 1]];
        for (int i = 1; i <= n; i++)
            if (!dist_id[i])
                gans = min(gans, pans + distances[dist_id[k_set[1]]][i] + distances[dist_id[k_set[k]]][i]);
    } while (next_permutation(k_set + 1, k_set + 1 + k));
    printf("%d", gans);
    return 0;
}

B – 砍树枝

这道题挺傻逼的。

每次砍掉一条边都会产生一个新的连通块,且这个连通块一定是一个子树和之外的点集。所以判断是否在同一个子树即可,直接用 DFS 序乱搞就行。

// B.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 200100, MAX_L = 23;

int head[MAX_N], current, n, q, dep[MAX_N], dfn[MAX_N], antidfn[MAX_N], ptot, edpt[MAX_N];

struct edge
{
    int from, to, nxt;
} edges[MAX_N << 1], org[MAX_N];

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

void dfs(int u, int fat)
{
    dep[u] = dep[fat] + 1, dfn[u] = ++ptot, antidfn[dfn[u]] = u;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fat)
            dfs(edges[i].to, u);
    edpt[u] = ptot;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d", &n);
    for (int i = 1, u, v; i <= n - 1; i++)
        scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u), org[i] = (edge){u, v, 0};
    dfs(1, 0), scanf("%d", &q);
    while (q--)
    {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        int up, low;
        up = org[z].from, low = org[z].to;
        if (dep[up] > dep[low])
            swap(up, low);
        bool xInLow = (dfn[low] <= dfn[x] && dfn[x] <= edpt[low]);
        bool yInLow = (dfn[low] <= dfn[y] && dfn[y] <= edpt[low]);
        if (xInLow ^ yInLow)
            puts("NO");
        else
            puts("YES");
    }
    return 0;
}

C – 搬砖

直接暴力,记录下每个点往右走的最近的砖块就行了。

// C.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;

struct block
{
    int l, r;
    bool operator<(const block &target) const { return l < target.l || (l == target.l && r < target.r); }
} bs[MAX_N];

int n, q, len, ci[MAX_N], suffix[MAX_N], pos[MAX_N];

int main()
{
    scanf("%d%d%d", &n, &q, &len);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &bs[i].l, &bs[i].r);
    sort(bs + 1, bs + 1 + n);
    for (int i = 1; i <= len + 1; i++)
        ci[i] = len + 1;
    for (int i = 1; i <= n; i++)
    {
        if (i > 1 && bs[i].l == bs[i - 1].l)
            continue;
        ci[bs[i].l] = bs[i].r;
    }
    suffix[len] = ci[len], pos[len] = len;
    for (int i = len - 1; i >= 1; i--)
    {
        suffix[i] = min(suffix[i + 1], ci[i]);
        pos[i] = suffix[i + 1] < ci[i] ? pos[i + 1] : i;
    }
    pos[len + 1] = len + 1;
    while (q--)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        int z = pos[x], res = 0;
        while (ci[z] <= y)
            res++, z = pos[ci[z] + 1];
        printf("%d\n", res);
    }
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *