Loading [MathJax]/extensions/tex2jax.js

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

A – 找位置

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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 序乱搞就行。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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 – 搬砖

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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 *