「SDOI2019」世界地图

你。 提交于 2020-01-03 20:02:24

Address

loj3112
luogu P5360
bzoj5531

Solution

对于 1im1\leq i\leq m,考虑分别预处理经度在 [1,i][1,i][i,m][i,m] 的点的 MST\text{MST}。询问的时候合并 [1,l1][1,l-1][r+1,m][r+1,m] 即可。

先考虑怎么预处理 [1,i][1,i]MST\text{MST}[i,m][i,m] 同理)。

假设我们已经有了 [1,i1][1,i-1]MST\text{MST},现在要在这里加上经度为 ii 的点和一些边。

考虑加入一条边 (u,v,w)(u,v,w) 会发生什么:

1.1. u,vu,v 不连通,连接 u,vu,v
2.2. u,vu,v 已经连通,且路径 uvu→v 的边的最大值 w\leq w,什么也不会发生。
3.3. u,vu,v 已经连通,且路径 uvu→v 的边的最大值 >w> w,断开这条最大边,连接 u,vu,v

也就是说,[1,i1][1,i-1]MST\text{MST} 中可能会有一些边被删掉。我们把 MST\text{MST}第一列和最后一列的点称为关键点,那么被删掉的边 ll 必定满足:存在关键点 x,yx,y 使得 ll 是路径 xyx→y 上的权值最大边。

换句话说,把端点的经度在 [1,i1][1,i-1] 的边全部拿出来跑 kruscal\text{kruscal}。边 ll 会连接两个连通块,如果这两个连通块里面都有关键点,那么 ll 可能被删掉,否则 ll 不可能被删掉。

因此记录边集 preipre_i 表示经度在 [1,i][1,i] 的点的 MST\text{MST} 中,之后可能被删的边。

[1,i1][1,i-1]MST\text{MST} 中,不在 prei1pre_{i-1} 的边(之后肯定不会被删的边)肯定都在 [1,i][1,i]MST\text{MST} 中。 假设 prei1pre_{i-1} 中的边的端点都是关键点,那么我们只要把 prei1pre_{i-1} 和新加入的 2n12n-1 条边一起拿出来跑 kruscal\text{kruscal},所得结果加上肯定不会被删的边,就是 [1,i][1,i]MST\text{MST}

可是 prei1pre_{i-1} 的边的端点不一定都是关键点,怎么办呢?

考虑 kruscal\text{kruscal} 的过程:

int fu = find(u), fv = find(v);
if (fu != fv) 在 MST 中加入边 (u, v, w);

其实和这样是等价的:

int fu = find(u), fv = find(v);
if (fu != fv) 在 MST 中加入边 (fu, fv, w);

假设 prei1pre_{i-1} 中的边都是关键点,那么可以考虑这样求出 preipre_i

inline void solve(vector<edge> &a, vector<edge> &b, ll &del)
{
    int len = a.size(), i;
    sort(a.begin(), a.end(), cmp);
    b.clear(); del = 0;
    for (i = 0; i < len; i++)
    {
        int x = a[i].x, y = a[i].y, v = a[i].v, fx = find(x), fy = find(y);
        if (fx == fy) del += v;
        else
        {
            if (bo[fx] && bo[fy]) link(fx, fy), b.push_back((edge){fx, fy, v}); 
            // 保证 b 中的边都是关键点
            else if (bo[fx]) link(fx, fy);
            else link(fy, fx);
        }
    }
}

其中 aaprei1pre_{i-1} 加上新的 2n12n-1 条边,box=1bo_x=1 表示 xx 是关键点,bbpreipre_i

这样我们就得到了 preipre_isufisuf_i 同理。

对于询问 (l,r)(l,r),只要把 prel1pre_{l-1}sufr+1suf_{r+1} 合并即可,方法跟已知 prei1pre_{i-1}preipre_i 差不多。

时间复杂度 O(nmlogn)O(nm\log n)

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

template <class t>
inline void read(t & res)
{
    char ch;
    while (ch = getchar(), !isdigit(ch));
    res = ch ^ 48;
    while (ch = getchar(), isdigit(ch))
    res = res * 10 + (ch ^ 48);
}

template <class t>
inline void print(t x)
{
    if (x > 9) print(x / 10);
    putchar(x % 10 + 48);
}

const int N = 105, M = 10005, T = N * M;
struct edge
{
    int x, y, v;
};
vector<edge> pre[M], suf[M];
int n, rht[N][M], dwn[N][M], m, f[T], lim, q;
bool bo[T];
unsigned int SA, SB, SC; 
ll pres[M], sufs[M], ans; 
// pres[i] 表示 [1,i] 的 MST 的边权之和,sufs[i] 同理

inline int getweight() 
{
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC % lim + 1;
}

inline void gen() 
{
    read(n); read(m); read(SA); read(SB); read(SC); read(lim);
    int i, j;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= m; j++) 
            rht[i][j] = getweight();
    for (i = 1; i < n; i++)
        for (j = 1; j <= m; j++) 
            dwn[i][j] = getweight();
}

inline int id(int x, int y)
{
    return (x - 1) * m + y;
}

inline int find(int x)
{
    return f[x] == x ? x : f[x] = find(f[x]);
}

inline bool cmp(const edge &a, const edge &b)
{
    return a.v < b.v;
}

inline void link(int x, int y)
{
    f[y] = x;
}

inline void upt(int x, bool y)
{
    f[x] = x;
    bo[x] = y;
}

inline void solve(vector<edge> &a, vector<edge> &b, ll &del)
{
    int len = a.size(), i;
    sort(a.begin(), a.end(), cmp);
    b.clear(); del = 0;
    for (i = 0; i < len; i++)
    {
        int x = a[i].x, y = a[i].y, v = a[i].v, fx = find(x), fy = find(y);
        if (fx == fy) del += v;
        else
        {
            if (bo[fx] && bo[fy]) link(fx, fy), b.push_back((edge){fx, fy, v});
            else if (bo[fx]) link(fx, fy);
            else link(fy, fx);
        }
    }
}

inline void init_pre()
{
    int i, j;
    for (i = 1; i <= n * m; i++) f[i] = i;
    ll del;
    vector<edge> a, b;
    for (i = 1; i <= m; i++)
    {
        for (j = 1; j <= n; j++)
        {
            upt(id(j, i), 1);
            upt(id(j, 1), 1);
            if (i > 2) upt(id(j, i - 1), 0);
        }
        a = pre[i - 1];
        pres[i] = pres[i - 1];
        for (j = 1; j <= n; j++)
        {
            if (i != 1)
            {
                a.push_back((edge){id(j, i - 1), id(j, i), rht[j][i - 1]});
                pres[i] += rht[j][i - 1];
            } 
            if (j != n)
            {
                a.push_back((edge){id(j, i), id(j + 1, i), dwn[j][i]});
                pres[i] += dwn[j][i];
            }
        }
        solve(a, b, del);
        pre[i] = b;
        pres[i] -= del;
    }
}

inline void init_suf()
{
    int i, j;
    ll del;
    for (i = 1; i <= n * m; i++) f[i] = i, bo[i] = 0;
    vector<edge> a, b;
    for (i = m; i >= 1; i--)
    {
        for (j = 1; j <= n; j++)
        {
            upt(id(j, i), 1);
            upt(id(j, m), 1);
            if (i < m - 1) upt(id(j, i + 1), 0);
        }
        a = suf[i + 1];
        sufs[i] = sufs[i + 1];
        for (j = 1; j <= n; j++)
        {
            if (i != m)
            {
                a.push_back((edge){id(j, i + 1), id(j, i), rht[j][i]});
                sufs[i] += rht[j][i];
            } 
            if (j != n)
            {
                a.push_back((edge){id(j, i), id(j + 1, i), dwn[j][i]});
                sufs[i] += dwn[j][i];
            }
        }
        solve(a, b, del);
        suf[i] = b;
        sufs[i] -= del;
    }
}

int main()
{
    gen();
    init_pre();
    init_suf();
    int l, r, i;
    read(q);
    for (i = 1; i <= n * m; i++) f[i] = i, bo[i] = 0;
    while (q--)
    {
        read(l); read(r);
        ans = pres[l - 1] + sufs[r + 1];
        vector<edge> a, b;
        for (i = 1; i <= n; i++)
        {
            ans += rht[i][m];
            a.push_back((edge){id(i, m), id(i, 1), rht[i][m]});
            upt(id(i, m), 0);
            upt(id(i, 1), 0);
            upt(id(i, l - 1), 0);
            upt(id(i, r + 1), 0);
        }
        int len = pre[l - 1].size();
        for (i = 0; i < len; i++) a.push_back(pre[l - 1][i]);
        len = suf[r + 1].size();
        for (i = 0; i < len; i++) a.push_back(suf[r + 1][i]);
        ll del = 0;
        solve(a, b, del);
        ans -= del;
        print(ans); putchar('\n');
    }
    return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!