Loading [MathJax]/extensions/tex2jax.js

「Fortuna OJ」Aug 12th – Group A 解题报告

A – 迷宫

这道题挺好的,让我知道了线段树还有这样的操作。

考虑线段树维护一段区间行入口到行出口的最短路,大概的维护方法非常像 Floyd。也没啥好说的,看代码吧。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// A.cpp
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
const int MAX_N = 2e5 + 1, INF = 0x3f3f3f3f;
int n, m, q, org[6][MAX_N];
struct node
{
int mp[6][6];
} nodes[MAX_N << 2];
void pushup(node &p, node &ls, node &rs)
{
memset(p.mp, 0x3f, sizeof(p.mp));
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
p.mp[i][j] = min(p.mp[i][j], ls.mp[i][k] + rs.mp[k][j]);
return;
}
void build(int l, int r, int p)
{
memset(nodes[p].mp, 0x3f, sizeof(nodes[p].mp));
if (l == r)
{
for (int i = 1; i <= n; i++)
if (org[i][l])
for (int j = i; j <= n; j++)
if (org[j][l])
nodes[p].mp[i][j] = nodes[p].mp[j][i] = j - i + 1;
else
break;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(nodes[p], nodes[lson], nodes[rson]);
}
void update(int qx, int l, int r, int p)
{
memset(nodes[p].mp, 0x3f, sizeof(nodes[p].mp));
if (l == r && l == qx)
{
for (int i = 1; i <= n; i++)
if (org[i][l])
for (int j = i; j <= n; j++)
if (org[j][l])
nodes[p].mp[i][j] = nodes[p].mp[j][i] = j - i + 1;
else
break;
return;
}
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(nodes[p], nodes[lson], nodes[rson]);
}
node query(int ql, int qr, int l, int r, int p)
{
if (ql <= l && r <= qr)
return nodes[p];
if (qr <= mid)
return query(ql, qr, l, mid, lson);
if (mid < ql)
return query(ql, qr, mid + 1, r, rson);
node fa, lft = query(ql, qr, l, mid, lson), rgt = query(ql, qr, mid + 1, r, rson);
pushup(fa, lft, rgt);
return fa;
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &org[i][j]);
build(1, m, 1);
while (q--)
{
int opt, a, b, c, d;
scanf("%d%d%d", &opt, &a, &b);
if (opt == 1)
org[a][b] ^= 1, update(b, 1, m, 1);
else
{
scanf("%d%d", &c, &d);
if (b > d)
puts("-1");
else
{
node nd = query(b, d, 1, m, 1);
if (nd.mp[a][c] == INF)
puts("-1");
else
printf("%d\n", nd.mp[a][c] - 1);
}
}
}
return 0;
}
// A.cpp #pragma GCC optimize(3) #include <bits/stdc++.h> #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) using namespace std; const int MAX_N = 2e5 + 1, INF = 0x3f3f3f3f; int n, m, q, org[6][MAX_N]; struct node { int mp[6][6]; } nodes[MAX_N << 2]; void pushup(node &p, node &ls, node &rs) { memset(p.mp, 0x3f, sizeof(p.mp)); for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) p.mp[i][j] = min(p.mp[i][j], ls.mp[i][k] + rs.mp[k][j]); return; } void build(int l, int r, int p) { memset(nodes[p].mp, 0x3f, sizeof(nodes[p].mp)); if (l == r) { for (int i = 1; i <= n; i++) if (org[i][l]) for (int j = i; j <= n; j++) if (org[j][l]) nodes[p].mp[i][j] = nodes[p].mp[j][i] = j - i + 1; else break; return; } build(l, mid, lson), build(mid + 1, r, rson); pushup(nodes[p], nodes[lson], nodes[rson]); } void update(int qx, int l, int r, int p) { memset(nodes[p].mp, 0x3f, sizeof(nodes[p].mp)); if (l == r && l == qx) { for (int i = 1; i <= n; i++) if (org[i][l]) for (int j = i; j <= n; j++) if (org[j][l]) nodes[p].mp[i][j] = nodes[p].mp[j][i] = j - i + 1; else break; return; } if (qx <= mid) update(qx, l, mid, lson); else update(qx, mid + 1, r, rson); pushup(nodes[p], nodes[lson], nodes[rson]); } node query(int ql, int qr, int l, int r, int p) { if (ql <= l && r <= qr) return nodes[p]; if (qr <= mid) return query(ql, qr, l, mid, lson); if (mid < ql) return query(ql, qr, mid + 1, r, rson); node fa, lft = query(ql, qr, l, mid, lson), rgt = query(ql, qr, mid + 1, r, rson); pushup(fa, lft, rgt); return fa; } int main() { scanf("%d%d%d", &n, &m, &q); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &org[i][j]); build(1, m, 1); while (q--) { int opt, a, b, c, d; scanf("%d%d%d", &opt, &a, &b); if (opt == 1) org[a][b] ^= 1, update(b, 1, m, 1); else { scanf("%d%d", &c, &d); if (b > d) puts("-1"); else { node nd = query(b, d, 1, m, 1); if (nd.mp[a][c] == INF) puts("-1"); else printf("%d\n", nd.mp[a][c] - 1); } } } return 0; }
// A.cpp
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

using namespace std;

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

int n, m, q, org[6][MAX_N];

struct node
{
    int mp[6][6];
} nodes[MAX_N << 2];

void pushup(node &p, node &ls, node &rs)
{
    memset(p.mp, 0x3f, sizeof(p.mp));
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                p.mp[i][j] = min(p.mp[i][j], ls.mp[i][k] + rs.mp[k][j]);
    return;
}

void build(int l, int r, int p)
{
    memset(nodes[p].mp, 0x3f, sizeof(nodes[p].mp));
    if (l == r)
    {
        for (int i = 1; i <= n; i++)
            if (org[i][l])
                for (int j = i; j <= n; j++)
                    if (org[j][l])
                        nodes[p].mp[i][j] = nodes[p].mp[j][i] = j - i + 1;
                    else
                        break;
        return;
    }
    build(l, mid, lson), build(mid + 1, r, rson);
    pushup(nodes[p], nodes[lson], nodes[rson]);
}

void update(int qx, int l, int r, int p)
{
    memset(nodes[p].mp, 0x3f, sizeof(nodes[p].mp));
    if (l == r && l == qx)
    {
        for (int i = 1; i <= n; i++)
            if (org[i][l])
                for (int j = i; j <= n; j++)
                    if (org[j][l])
                        nodes[p].mp[i][j] = nodes[p].mp[j][i] = j - i + 1;
                    else
                        break;
        return;
    }
    if (qx <= mid)
        update(qx, l, mid, lson);
    else
        update(qx, mid + 1, r, rson);
    pushup(nodes[p], nodes[lson], nodes[rson]);
}

node query(int ql, int qr, int l, int r, int p)
{
    if (ql <= l && r <= qr)
        return nodes[p];
    if (qr <= mid)
        return query(ql, qr, l, mid, lson);
    if (mid < ql)
        return query(ql, qr, mid + 1, r, rson);
    node fa, lft = query(ql, qr, l, mid, lson), rgt = query(ql, qr, mid + 1, r, rson);
    pushup(fa, lft, rgt);
    return fa;
}

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf("%d", &org[i][j]);
    build(1, m, 1);
    while (q--)
    {
        int opt, a, b, c, d;
        scanf("%d%d%d", &opt, &a, &b);
        if (opt == 1)
            org[a][b] ^= 1, update(b, 1, m, 1);
        else
        {
            scanf("%d%d", &c, &d);
            if (b > d)
                puts("-1");
            else
            {
                node nd = query(b, d, 1, m, 1);
                if (nd.mp[a][c] == INF)
                    puts("-1");
                else
                    printf("%d\n", nd.mp[a][c] - 1);
            }
        }
    }
    return 0;
}

B – 猛汉王

这道题真毒瘤。

我们分别把有瓶子的和没瓶子的分为黑色点和白色点。整个问题就变成了:在一个图上,把一些无向边的方向进行标记,然后找出一种方案能让单向三角形最多,其中我们只需要求最大值就行了(当然了,最小值的求法是非常相似的)。

我们发现端点异色的边的方向跟 Manhattan 距离和参数 d 相关,所以我们可以尝试预处理一个数组

cover[i]
cover[i]代表与点\(i\) Manhattan 距离小于\(d\)的点的个数,其中我们可以扩展一下,设
cover[i, j]
cover[i, j]与\(i, j\)两点 Manhattan 距离均小于\(d\)的点的个数。最后,最大值的答案显然是:

\[ max_ans = \sum_{i, j \in White} max\{ cover[i] – cover[i, j], cover[j] – cover[i. j] \} \]

进行一定的变换:

\[ max_ans = \sum_{i, j\in White} max\{ cover[i], cover[j] \} – cover[i, j] \]

发现\(cover[i, j]\)其实就是对于每一个黑点可选的 Manhattan 距离小于\(d\)的白点个数:

\[ max_ans = \sum_{i, j\in White} max\{ cover[i], cover[j] \} – \sum_{u \in Black} {cover[u] \choose 2} \]

所以我们现在需要计算出\(cover[]\)来进行这个计算。直接求曼哈顿距离小于\(d\)的点数有点困难,我们考虑把一个点的坐标系进行「翻折」,从\((x, y) \to (x + y, x – y)\)。我们会发现,翻折坐标系之后,考虑两点之间的 Manhattan 距离就变成了考虑两点之间的「切比雪夫距离」(\(max\{|x_i – x_j|, |y_i – y_j|\}\),发现变换坐标系之后带入满足绝对值不等式,也就是 Manhattan 距离的定义)。所以,围绕新的坐标,发现\(cover[i]\)等于以点\(i\)为中心半径为\(D\)的正方形内的点数,这就是扫描线经典问题了(POJ 2482),套上就行。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// B.cpp
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define ll long long
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
const int MAX_N = 1e5 + 200;
int n, m, d, tree[MAX_N << 2];
long long min_ans = 0, max_ans = 0, minusComb = 0;
vector<ll> mapping, xlist;
template <class T>
inline T read(T &x)
{
T data = 0;
int w = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (isdigit(ch))
data = 10 * data + ch - '0', ch = getchar();
return x = data * w;
}
inline int lowbit(int x) { return x & -x; }
void add(int x, int d)
{
int siz = mapping.size();
for (; x <= siz; x += lowbit(x))
tree[x] += d;
}
int query(int x)
{
int ans = 0;
for (; x; x -= lowbit(x))
ans += tree[x];
return ans;
}
struct point
{
ll x, y;
bool operator<(const point &pt) const { return x < pt.x || (x == pt.x && y < pt.y); }
} pts1[MAX_N], pts2[MAX_N];
struct quad
{
ll x, y, aff;
bool operator<(const quad &qd) const { return x < qd.x; }
};
vector<quad> vec;
int cover[MAX_N];
int ripe(ll x) { return lower_bound(mapping.begin(), mapping.end(), x) - mapping.begin() + 1; }
void solve()
{
memset(tree, 0, sizeof(tree));
vec.clear(), xlist.clear(), mapping.clear();
for (int i = 1; i <= m; i++)
{
vec.push_back(quad{pts2[i].x - d, pts2[i].y, 1});
vec.push_back(quad{pts2[i].x + d + 1, pts2[i].y, -1});
xlist.push_back(pts2[i].x - d), xlist.push_back(pts2[i].x + d + 1);
mapping.push_back(pts2[i].y);
}
for (int i = 1; i <= n; i++)
{
xlist.push_back(pts1[i].x);
mapping.push_back(pts1[i].y - d - 1), mapping.push_back(pts1[i].y + d);
}
sort(xlist.begin(), xlist.end()), sort(mapping.begin(), mapping.end());
xlist.erase(unique(xlist.begin(), xlist.end()), xlist.end());
mapping.erase(unique(mapping.begin(), mapping.end()), mapping.end());
sort(vec.begin(), vec.end());
int cur1 = 0, cur2 = 1;
for (ll x : xlist)
{
while (cur1 < vec.size() && vec[cur1].x == x)
add(ripe(vec[cur1].y), vec[cur1].aff), cur1++;
while (cur2 <= n && pts1[cur2].x == x)
cover[cur2] = query(ripe(pts1[cur2].y + d)) - query(ripe(pts1[cur2].y - d - 1)), cur2++;
}
sort(cover + 1, cover + 1 + n);
for (int i = 1; i <= n; i++)
{
min_ans += 1LL * (n - i) * cover[i];
max_ans += 1LL * (i - 1) * cover[i];
minusComb += 1LL * (1LL * cover[i] * (cover[i] - 1) >> 1);
}
}
int main()
{
/*
freopen("mhw.in", "r", stdin);
freopen("mhw.out", "w", stdout);
*/
read(n), read(m), read(d);
for (int i = 1, x, y; i <= n; i++)
{
read(x), read(y);
pts1[i].x = x + y, pts1[i].y = x - y;
}
for (int i = 1, x, y; i <= m; i++)
{
read(x), read(y);
pts2[i].x = x + y, pts2[i].y = x - y;
}
sort(pts1 + 1, pts1 + 1 + n);
sort(pts2 + 1, pts2 + 1 + m);
solve();
swap(n, m), swap(pts1, pts2);
solve();
printf("%lld %lld", min_ans - minusComb, max_ans - minusComb);
return 0;
}
// B.cpp #pragma GCC optimize(3) #include <bits/stdc++.h> #define ll long long #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) using namespace std; const int MAX_N = 1e5 + 200; int n, m, d, tree[MAX_N << 2]; long long min_ans = 0, max_ans = 0, minusComb = 0; vector<ll> mapping, xlist; template <class T> inline T read(T &x) { T data = 0; int w = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); } while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); return x = data * w; } inline int lowbit(int x) { return x & -x; } void add(int x, int d) { int siz = mapping.size(); for (; x <= siz; x += lowbit(x)) tree[x] += d; } int query(int x) { int ans = 0; for (; x; x -= lowbit(x)) ans += tree[x]; return ans; } struct point { ll x, y; bool operator<(const point &pt) const { return x < pt.x || (x == pt.x && y < pt.y); } } pts1[MAX_N], pts2[MAX_N]; struct quad { ll x, y, aff; bool operator<(const quad &qd) const { return x < qd.x; } }; vector<quad> vec; int cover[MAX_N]; int ripe(ll x) { return lower_bound(mapping.begin(), mapping.end(), x) - mapping.begin() + 1; } void solve() { memset(tree, 0, sizeof(tree)); vec.clear(), xlist.clear(), mapping.clear(); for (int i = 1; i <= m; i++) { vec.push_back(quad{pts2[i].x - d, pts2[i].y, 1}); vec.push_back(quad{pts2[i].x + d + 1, pts2[i].y, -1}); xlist.push_back(pts2[i].x - d), xlist.push_back(pts2[i].x + d + 1); mapping.push_back(pts2[i].y); } for (int i = 1; i <= n; i++) { xlist.push_back(pts1[i].x); mapping.push_back(pts1[i].y - d - 1), mapping.push_back(pts1[i].y + d); } sort(xlist.begin(), xlist.end()), sort(mapping.begin(), mapping.end()); xlist.erase(unique(xlist.begin(), xlist.end()), xlist.end()); mapping.erase(unique(mapping.begin(), mapping.end()), mapping.end()); sort(vec.begin(), vec.end()); int cur1 = 0, cur2 = 1; for (ll x : xlist) { while (cur1 < vec.size() && vec[cur1].x == x) add(ripe(vec[cur1].y), vec[cur1].aff), cur1++; while (cur2 <= n && pts1[cur2].x == x) cover[cur2] = query(ripe(pts1[cur2].y + d)) - query(ripe(pts1[cur2].y - d - 1)), cur2++; } sort(cover + 1, cover + 1 + n); for (int i = 1; i <= n; i++) { min_ans += 1LL * (n - i) * cover[i]; max_ans += 1LL * (i - 1) * cover[i]; minusComb += 1LL * (1LL * cover[i] * (cover[i] - 1) >> 1); } } int main() { /* freopen("mhw.in", "r", stdin); freopen("mhw.out", "w", stdout); */ read(n), read(m), read(d); for (int i = 1, x, y; i <= n; i++) { read(x), read(y); pts1[i].x = x + y, pts1[i].y = x - y; } for (int i = 1, x, y; i <= m; i++) { read(x), read(y); pts2[i].x = x + y, pts2[i].y = x - y; } sort(pts1 + 1, pts1 + 1 + n); sort(pts2 + 1, pts2 + 1 + m); solve(); swap(n, m), swap(pts1, pts2); solve(); printf("%lld %lld", min_ans - minusComb, max_ans - minusComb); return 0; }
// B.cpp
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define ll long long
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

using namespace std;

const int MAX_N = 1e5 + 200;

int n, m, d, tree[MAX_N << 2];
long long min_ans = 0, max_ans = 0, minusComb = 0;

vector<ll> mapping, xlist;

template <class T>
inline T read(T &x)
{
    T data = 0;
    int w = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (isdigit(ch))
        data = 10 * data + ch - '0', ch = getchar();
    return x = data * w;
}

inline int lowbit(int x) { return x & -x; }

void add(int x, int d)
{
    int siz = mapping.size();
    for (; x <= siz; x += lowbit(x))
        tree[x] += d;
}

int query(int x)
{
    int ans = 0;
    for (; x; x -= lowbit(x))
        ans += tree[x];
    return ans;
}

struct point
{
    ll x, y;
    bool operator<(const point &pt) const { return x < pt.x || (x == pt.x && y < pt.y); }
} pts1[MAX_N], pts2[MAX_N];

struct quad
{
    ll x, y, aff;
    bool operator<(const quad &qd) const { return x < qd.x; }
};
vector<quad> vec;

int cover[MAX_N];

int ripe(ll x) { return lower_bound(mapping.begin(), mapping.end(), x) - mapping.begin() + 1; }

void solve()
{
    memset(tree, 0, sizeof(tree));
    vec.clear(), xlist.clear(), mapping.clear();
    for (int i = 1; i <= m; i++)
    {
        vec.push_back(quad{pts2[i].x - d, pts2[i].y, 1});
        vec.push_back(quad{pts2[i].x + d + 1, pts2[i].y, -1});

        xlist.push_back(pts2[i].x - d), xlist.push_back(pts2[i].x + d + 1);

        mapping.push_back(pts2[i].y);
    }

    for (int i = 1; i <= n; i++)
    {
        xlist.push_back(pts1[i].x);
        mapping.push_back(pts1[i].y - d - 1), mapping.push_back(pts1[i].y + d);
    }

    sort(xlist.begin(), xlist.end()), sort(mapping.begin(), mapping.end());
    xlist.erase(unique(xlist.begin(), xlist.end()), xlist.end());
    mapping.erase(unique(mapping.begin(), mapping.end()), mapping.end());

    sort(vec.begin(), vec.end());
    int cur1 = 0, cur2 = 1;
    for (ll x : xlist)
    {
        while (cur1 < vec.size() && vec[cur1].x == x)
            add(ripe(vec[cur1].y), vec[cur1].aff), cur1++;
        while (cur2 <= n && pts1[cur2].x == x)
            cover[cur2] = query(ripe(pts1[cur2].y + d)) - query(ripe(pts1[cur2].y - d - 1)), cur2++;
    }

    sort(cover + 1, cover + 1 + n);

    for (int i = 1; i <= n; i++)
    {
        min_ans += 1LL * (n - i) * cover[i];
        max_ans += 1LL * (i - 1) * cover[i];
        minusComb += 1LL * (1LL * cover[i] * (cover[i] - 1) >> 1);
    }
}

int main()
{
    /*
    freopen("mhw.in", "r", stdin);
    freopen("mhw.out", "w", stdout);
    */
    read(n), read(m), read(d);
    for (int i = 1, x, y; i <= n; i++)
    {
        read(x), read(y);
        pts1[i].x = x + y, pts1[i].y = x - y;
    }
    for (int i = 1, x, y; i <= m; i++)
    {
        read(x), read(y);
        pts2[i].x = x + y, pts2[i].y = x - y;
    }
    sort(pts1 + 1, pts1 + 1 + n);
    sort(pts2 + 1, pts2 + 1 + m);

    solve();
    swap(n, m), swap(pts1, pts2);

    solve();

    printf("%lld %lld", min_ans - minusComb, max_ans - minusComb);
    return 0;
}

 

One Comment

Leave a Reply

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