世界の「SDOI2019」マップ(互いに素セット+ kruscal)

住所

loj3112

luogu P5360

bzoj5531

解決

以下のための\(1 \のLeq I \のLeq M \) 別々に前処理された経度と考え\([1、I] \)、\ ([I、M] \)(\ \テキスト{MST} \ ) 。複合クエリ場合\([1、L-1 ] \) と\([R + 1、M ] \) へ。

どのように前処理考える\([1、i]は\ ) の\(\テキストMST} {\)(\ ([I、M] \)と同様)。

我々が持っていると仮定\([1、I-1 ] \) の(テキストMST} {\ \)\今経度を追加し、\(I \)点とエッジの数。

エッジを追加することを検討((U、V、W \ )\) 何が起こりますか:

\(1 \) \(U、V \)接続されていない場合、接続\(U、V \)
\(2 \) \(U、V \)が連通されており、パス\(U→V \)最大側(\ \のLeq W \) 何も起こりません。
\(3 \) \(Uは、V \)が連通されており、パス\(U→V \)最大側\(> W \) この最大エッジは、接続を切断\(U、V \) 。

すなわち、([1 ,. 1-I] \)\(\ \テキスト{MST} \ ) の縁の一部が削除されてもよいです。我々\(\テキスト{MST} \ ) における最初の列と最後の点が臨界点と呼ばれ、その後、エッジが削除された\(Lが\)を満足しなければならない:臨界点の存在\(X、Y \)ように\(L \)パスである(X→Y \)\最大側の重量。

すなわち、経度内のエンドポイントで\([1、I-1 ] \) すべてのエッジの切れ(\ \テキストkruscalを} {\) エッジ\(L \)接続二つの通信ブロックは、2つのブロックが通信鍵がある場合、次に\(Lは\)を削除してもよい、または\(L \)を削除することはできません。

そう記録エッジ設定すること\(pre_iが\)経度を表し\([1、i]の\ ) 点(\ \テキスト{MST} \ ) 側が削除されてもよいした後に、。

\([1、I-1 ] \) の\(\テキスト{MST} \ ) 、NOT IN \(pre_ {I-1} \) エッジ(必ずエッジの後に削除されない)確かである\ ([1、i]は\)\(\テキスト{MST} \ ) です。仮定(pre_ {I-1} \ \) キーポイントの端部側である限り、我々\(pre_ {I-1} \) と、新たに追加された(2N-1 \)\ストリップテイク一緒になくなった(\テキストkruscal} {\)\、肯定的な結果は、一緒に消去されていないエッジである([1、i]を\ \ ) の\(\テキストMST} {\)

しかし、\(pre_ {I-1} \) エンドポイント側はそれを行う方法を、必ずしも重要なポイントではありませんか?

検討\(\テキスト\ {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);

仮定({I-1} \ \ pre_) キーポイントは、その後得られるの側面を考慮することができる(pre_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);
        }
    }
}

前記\(A \)がある(pre_ {I-1} \ \) を加えた新たな\(2N-1 \)エッジ、\(1 bo_x = \)を表す\(Xを\)キーポイントである(\ B \)です\(pre_i \)

このように、我々が得る\(pre_i \)、\ (suf_i \)共感を。

問い合わせ\((L、R&LT)\) 限り、\(pre_ {L-1} \) と\(suf_ {R + 1} \) 公知の方法を用いて、マージされ\(pre_ {I-1 } \)を求める\(pre_i \)ほとんど。

時間複雑\(O(NM \ N-ログ)\)

コード

#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;
}

おすすめ

転載: www.cnblogs.com/cyf32768/p/12196019.html