[ペアリング] UOJ388ツリー(木+セグメントツリー上DSU)

ポータル

問題の意味:
を含む所定の\(N- \)は、所定の長さの後に、無根ツリーノード\(M \)シーケンスの各要素\([1、N] \ ) の間。
今でも最小のツリーを完了するための各時間間隔のシーケンスの長さは、整合点の各ペアのペアリングプロセスの間の距離の合計として定義されます。
今、すべての時間の必要な長さを完了するために、さらには間隔。

アイデア:

  • まず、それが根付いツリーに古い木は、それが最終的な答えには影響しませんかもしれません。
  • 自然こと注:マッチングポイントの偶数が一意である二十から二の方法は、エッジのない二重カウントがないよう確保するように、2つが一致の最深点です。
  • (部分QAQことを最初に)たくさんのことを考慮して、サブツリー内に直接計算にカウントされません。唯一の方法が一致しているので、サブツリーのすべてのマッチが唯一最大のポイントに残し、完了した場合。もちろん、サブツリーと彼の父親は確かに、このエッジをカウントしますポイントが残っている場合。
  • 我々は、偶数間隔奇数の寄与は、サブツリーのエッジが現れるの要素のシーケンス番号であり、一方の側に別個の寄与に問題を検討します。
  • 存在する場合、接頭辞を行い、その後、配列タグでマークされた現在のサブツリー、暴力のためにと:暴力計算を考えてみましょう(I、J、I <J \)\満たし、\(I \当量J(MOD \ 2)\ \(s_j \当量S_I + 1 (MOD \ 2)\) ことができます。
  • メンテナンスのため、ツリーラインならば、あなただけの奇妙な位置を維持する必要がある、接頭辞ダイ上でも、位置\(2 \)の意味で\(1 \)すぐに現在のサブツリー内の答えを得るために数。
  • 時間複雑\(O(N-2logn ^)\)
  • それは、サブツリーの問題に関連し、そしてあなたが直接再生できるように、バンドを変更していないので(DSU \ ON \木\)\、最終的に複雑です\(O(nlog ^ 2n個)\)

この感覚は、一方が日常のようです質問にサブサブツリー+木内の問題でしょうか?(最終atcoderも、問題があります)。
この後には、個々の要素の寄与を考慮すると、私の考えを変更しようとする質問の寄与を計算することができます。
この問題は、直接書き込みにツリーラインをマージすることができ、複雑さがある\(O(nlogn)\)が、(ない書き込み)書き込みするのが面倒。
コードは以下の通りであります:

/*
 * Author:  heyuhhh
 * Created Time:  2019/11/16 8:54:36
 */
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
//#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5, MOD = 998244353;

template <class T>
inline void read(T& x) {
    static char c;
    x = 0;
    bool sign = 0;
    while (!isdigit(c = getchar()))
        if (c == '-')
            sign = 1;
    for (; isdigit(c); x = x * 10 + c - '0', c = getchar())
        ;
    if (sign)
        x = -x;
}

int n, m;
int a[N];
struct Edge{
    int v, w, next;   
}e[N << 1];
int head[N], tot;
void adde(int u, int v, int w) {
    e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;
}

int pre[N], last[N];
int sz[N], bson[N], son;

void dfs(int u, int fa) {
    int mx = 0; sz[u] = 1;
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if(v != fa) {
            a[v] = e[i].w;
            dfs(v, u);
            sz[u] += sz[v];
            if(sz[v] > mx) mx = sz[v], bson[u] = v;
        }
    }  
}

int odd[N << 2], even[N << 2], rev[N << 2];
int ans;

void Reverse(int o, int l, int r) {
    if(l == r) {
        if(l & 1) odd[o] ^= 1;
        else even[o] ^= 1;
    } else {
        odd[o] = (r + 1) / 2 - l / 2 - odd[o];
        even[o] = r / 2 - (l - 1) / 2 - even[o];
    }
    rev[o] ^= 1;
}

void push_up(int o) {
    odd[o] = odd[o << 1] + odd[o << 1|1];   
    even[o] = even[o << 1] + even[o << 1|1];
}

void push_down(int o, int l, int r) {
    if(rev[o]) {
        int mid = (l + r) >> 1;
        Reverse(o << 1, l, mid);
        Reverse(o << 1|1, mid + 1, r);
        rev[o] = 0;
    }   
}

void upd(int o, int l, int r, int L, int R) {
    if(L <= l && r <= R) {
        Reverse(o, l, r);
        return;
    }
    push_down(o, l, r);
    int mid = (l + r) >> 1;
    if(L <= mid) upd(o << 1, l, mid, L, R);
    if(R > mid) upd(o << 1|1, mid + 1, r, L, R);
    push_up(o);
}

int Get() {
    int res = (1ll * (m / 2 + 1 - even[1]) * even[1] % MOD + 1ll * ((m + 1) / 2 - odd[1]) * odd[1] % MOD) % MOD;
    return res;
}

void calc(int u, int fa) {
    for(int i = last[u]; i; i = pre[i]) upd(1, 1, m, i, m);
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if(v == fa || v == son) continue;
        calc(v, u);
    }   
}

void dfs2(int u, int fa, int op) {
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if(v != fa && v != bson[u]) dfs2(v, u, 0);    
    }
    if(bson[u]) dfs2(bson[u], u, 1);
    son = bson[u];
    calc(u, fa);
    son = 0;
    dbg(u, get());
    ans = (ans + 1ll * a[u] * Get() % MOD) % MOD;
    if(!op) calc(u, fa);
}

void run(){
    memset(head, -1, sizeof(head));
    read(n), read(m);
    for(int i = 1; i < n; i++) {
        int u, v, w;
        read(u), read(v), read(w);
        adde(u, v, w); adde(v, u, w);
    }
    for(int i = 1; i <= m; i++) {
        int x; read(x);
        pre[i] = last[x];
        last[x] = i;
    }
    dfs(1, 0);
    dfs2(1, 0, 1);
    cout << ans << '\n';
}

int main() {
    run();
    return 0;
}

おすすめ

転載: www.cnblogs.com/heyuhhh/p/11873131.html