[SOJ647]私は祭りを望む[貪欲]

問題の意味の説明:指定された\(N- \)点、\(m個\)連結グラフと右側の縁ではないが、各エッジは黒と白であってもよいです。それは、少なくとも少なくとも一つの黒色側と白色側を含有する場合にのみ、スパニングツリーの方法を定義しています。法定最低の右側には、スパニングツリーと正確になるように対数、プロトコルを染色\(X- \) \(N- \ ^のLeq 10 5、\ ^タイムズ10 5 M個の\のLeq 2、X \ ^ 18のLeq 10 \です)


一つの結論:ツリースパニング法定最小の任意の法的な染色プロトコルの\(E_1 \)を、元のグラフの最小全域木が存在しなければならない\(E_2 \)ように、\(E_1 \)が一つだけエッジを有することができます存在しません\(E_2 \)をして。

証明:いずれかの場合には\(E_1、E_2 \) 存在している\(E_1 \)両側における\(E_1、E_2 \) 満足\(E_1、E_2 E_2 \でない\ \)は、明らかに\(len_ {E_1}、len_ {E_2} \) 、それらの交換量および両側よりも大きいです。我々は仮定することができる(E_2 \)\側面は、白色である\(E_1、E_2 \)少なくとも片面が黒有します。したがって、ここで黒または白の側縁交換\(E_2 \)対応するエッジ、答えが良好でなければなりません。

したがって、任意の画像は、最小スパニングツリーを得ると呼ぶことができる\(T \) その重みが設定されている\(S \)

もし\(S> X- \) 明らかに無ソリューション。

もし\(X-S = \) 明らかに任意の最小スパニングツリーの画像が正当であることができます。列挙されていない考える(T \)を\各エッジが明らかにだけ置き換え、最小スパニングツリーにその最適体重を強制得られる\(T \)最大に右側の値チェーン内を。仮定\(EQ \)の場合にのみ、染色プロトコルが有効でない、不変の重みを満たし、交換縁\(T \)\(N-1 \)エッジと\(EQ \ )エッジが交換可能な同じ色であるストリップ、答えは^ 2 ^ {M} -2- EQのMn + 2 {} \)(\します

それ以外の場合は\(S <X- \) オリジナルと任意の重み(<X \)\スパニングツリーは法的に不可能です。まだ列挙しない\(T \)を各エッジが設けられている\(EQの\)正確に重みを満たし、交換縁\(X- \)、\ (LE \)は重みを置き換える満たす縁そして(<X \)\、溶液が法的満たすために必要とされることは明らかである\(T \)\(N-1 \)エッジと\(LE \)ストリップと交換後の重量を\(<X \を)側面は同じ色です。この文脈において、染色プロトコルは、場合にのみ有効でない\(EQ \)は、別の側面が同じ色の縁の上に、答えがされているストリップ(2 ^ {MNル\ + 2} -2 ^ {MNル+ 2} -eq \)

そして、私がハングアップ曲が長い時間のために書くために倍増しました

#include <cstdio>
#include <cctype>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#define R register
#define ll long long
using namespace std;
const int N = 110000, M = 210000, mod = 1e9 + 7;

int t, n, m, q, hd[N], nxt[M], to[M], val[M], noedg, st[N][17], maxV[N][17], dep[N];
ll lim, sum;
struct node {
    int x, y, w, used;
    inline bool operator < (const node &a) const {
        return w < a.w;
    }
}edg[M];

namespace dsu {
///
int fa[N];

inline void init(int n) {
    for (R int i = 1; i <= n; ++i)
        fa[i] = i;
    return;
}

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

inline void unite(int x, int y) {
    fa[find(x)] = find(y);
    return;
}
///
}

inline void init() {
    dsu::init(n), noedg = 1, sum = 0;
    for (R int i = 1; i <= n; ++i)
        hd[i] = 0;
    return;
}

template <class T> inline void read(T &x) {
    x = 0;
    char ch = getchar(), w = 0;
    while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    x = w ? -x : x;
    return;
}

inline void addEdg(int x, int y, int w) {
    nxt[++noedg] = hd[x], hd[x] = noedg, to[noedg] = y, val[noedg] = w;
    nxt[++noedg] = hd[y], hd[y] = noedg, to[noedg] = x, val[noedg] = w;
    return;
}

void dfs1(int now) {
    dep[now] = dep[st[now][0]] + 1;
    for (R int i = 1; i <= 16; ++i) {
        maxV[now][i] = max(maxV[now][i - 1], maxV[st[now][i - 1]][i - 1]);
        st[now][i] = st[st[now][i - 1]][i - 1];
    }
    for (R int i = hd[now], v; i; i = nxt[i]) {
        if ((v = to[i]) == st[now][0]) continue;
        maxV[v][0] = val[i], st[v][0] = now, dfs1(v);
    }
    return;
}

inline int findMax(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    int ret = 0;
    for (R int i = 16; ~i; --i)
        if (dep[st[x][i]] >= dep[y])
            ret = max(ret, maxV[x][i]), x = st[x][i];
    if (x == y) return ret;
    for (R int i = 16; ~i; --i)
        if (st[x][i] != st[y][i])
            ret = max(ret, max(maxV[x][i], maxV[y][i])), x = st[x][i], y = st[y][i];
    return max(ret, max(maxV[x][0], maxV[y][0]));
}

inline ll quickpow(ll base, ll pw) {
    ll ret = 1;
    while (pw) {
        if (pw & 1) ret = ret * base % mod;
        base = base * base % mod, pw >>= 1;
    }
    return ret;
}

int main() {
    read(t);
    int x, y;
    while (t--) {
        read(n), read(m), read(lim);
        init();
        for (R int i = 1; i <= m; ++i)  
            read(edg[i].x), read(edg[i].y), read(edg[i].w), edg[i].used = 0;
        sort(edg + 1, edg + 1 + m);
        for (R int i = 1; i <= m; ++i) {
            x = edg[i].x, y = edg[i].y;
            if (dsu::find(x) != dsu::find(y))
                dsu::unite(x, y), edg[i].used = 1, sum += edg[i].w, addEdg(x, y, edg[i].w);
        }
        if (sum > lim) {
            printf("0\n");
            continue;
        }
        dfs1(1);
        int numL = 0, numE = 0;
        for (R int i = 1; i <= m; ++i) {
            if (edg[i].used) continue;
            int v = findMax(edg[i].x, edg[i].y);
            if (sum - v + edg[i].w < lim)
                ++numL;
            else if (sum - v + edg[i].w == lim)
                ++numE;
        }
        if (lim == sum)
            printf("%lld\n", (quickpow(2, m) + mod - quickpow(2, m - n + 2 - numE)) % mod);
        else
            printf("%lld\n", (quickpow(2, m - n + 2 - numL) - quickpow(2, m - n + 2 - numL - numE) + mod) % mod);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/suwakow/p/11720873.html