@codechef - MXMN @最大値と最小値


@説明@

すべての権利のパス定義関数F(G、X、Y)G量(経路の各側の最大重量)の点xとyとの間の中点は、Gは無向右側である最小値であります図通信。
グラフG1とG2接続M二つのエッジのN点所与。動作してください:
\ [S = \ sum_ {I = 1} ^ {N-1} \ sum_ {J = I + 1} ^ {B} F(ジーエル、I、J)* F(G2、I、J )\ MOD 998244353 \]

入力フォーマット
入力の最初の行のは、二つの整数N及びMを含有します
次のMラインが三つの整数、U、VおよびWが含まれ、G1は、点uおよびv wはエッジコネクタの重量で表しています。
そして、次のMラインが三つの整数、U、VおよびWが含まれ、G2は、uとv wはエッジコネクタの重量で表します。

出力フォーマット
各試験について、出力ラインは整数を含み、Sはモジュロ998244353の結果を表します。

データ範囲
•^ 1≤N 5 10≤
2N = M•
•。1≤U、V≤N
•^ 1 8 10≤W≤
•GLとG2は、図を連通しています。

サンプルデータ
入力
。3. 6
。1 2 3
2 3 1
3 1 2
。1 4 2
2 3 5
。3. 1. 6
1 2 2
2 3 1
。3. 1. 3
。1. 5 2
2. 3. 4
。3. 1. 6
の出力
9

@溶液@

検討最初の二つは、図のG1、木T1、T2のG2クラスカル再構成を構築した、問題は次のようになる。
。。[S = \ sum_ = {I} \ 1 1-N ^ {} \ {sum_ 1 J = I + } ^ {N} T1.key(T2.lca (I、J))* T2.key(T2.lca(I、J))\]

重みLCA 2本の木を見つけ、実際にはサイドパーティングツリーの製品は、古典的なレパートリーをマージします。
私たちは(クラスカル自体がバイナリツリーでツリーを再構築し、そうではない再建を行うため)ツリーエッジポイントを構築するために、あそこ彼の息子彼の息子より深く保管センターの右側に小さな深ストレージセンター側の通信ブロックを残し、再びサイドパーティションを考えます側通信ブロック。
交差路の中心側(M1、M2)の(u、v)は小さい深さLCAブロックのみ通信の関連部分と、それは、uが小さい深さでLCAを思い出すことができる(U、V)= LCA (uが、M1)。希望uはT1.key(LCA(U、M1)に対応する ) 、[U] Fダウンストレージと呼びます。

列挙T2.lcaは、(i、j)の総和を算出対応するP T1.keyあります。統計答えながら、サブツリーエッジを与えるために結合息子のp個のPサブツリーの左側と右側を考えてみましょう。
CNT向こう大きい深さを点の数を維持し、そこfは全加算和をより小さなサブ点の木のメンテナンス側を考えます。和ツリーとCNTペアワイズにより分割された2つの側面は、我々は統合を取得したい事柄をまとめました。

@acceptedコード@

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 200000;
const int MOD = 998244353;
int lg[2*MAXN + 5];
struct Graph{
    struct edge{
        int to; bool tag;
        edge *nxt, *rev;
    }edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt;
    Graph() {ecnt = &edges[0];}
    void addedge(int u, int v) {
        edge *p = (++ecnt), *q = (++ecnt);
        p->to = v, p->nxt = adj[u], adj[u] = p, p->tag = false;
        q->to = u, q->nxt = adj[v], adj[v] = q, q->tag = false;
        p->rev = q, q->rev = p;
    }
    int dep[MAXN + 5], dfn[2*MAXN + 5], fir[MAXN + 5], dcnt;
    void dfs(int x, int f) {
        dep[x] = dep[f] + 1, dfn[++dcnt] = x, fir[x] = dcnt;
        for(edge *p=adj[x];p;p=p->nxt) {
            if( p->to == f ) continue;
            dfs(p->to, x), dfn[++dcnt] = x;
        }
    }
    int st[20][2*MAXN + 5];
    void get_st() {
        for(int i=1;i<=dcnt;i++)
            st[0][i] = dfn[i];
        for(int j=1;j<20;j++) {
            int t = 1<<(j-1);
            for(int i=1;i+t<=dcnt;i++)
                st[j][i] = (dep[st[j-1][i]] < dep[st[j-1][i+t]]) ? st[j-1][i] : st[j-1][i+t];
        }
    }
    void build(int x) {dcnt = 0; dfs(x, 0); get_st();}
    int lca(int x, int y) {
        if( fir[x] > fir[y] ) swap(x, y);
        x = fir[x], y = fir[y];
        int k = lg[y-x+1], l = (1<<k);
        return (dep[st[k][x]] < dep[st[k][y-l+1]]) ? st[k][x] : st[k][y-l+1];
    }
}G1, G2;
int siz[MAXN + 5];
bool cmp(Graph::edge *a, Graph::edge *b, int tot) {
    if( a == NULL ) return false;
    if( b == NULL ) return true;
    return max(siz[a->to], tot-siz[a->to]) < max(siz[b->to], tot-siz[b->to]);
}
Graph::edge *get_mid(int x, int f, int tot) {
    Graph::edge *ret = NULL; siz[x] = 1;
    for(Graph::edge *p=G1.adj[x];p;p=p->nxt) {
        if( p->tag || p->to == f ) continue;
        Graph::edge *tmp = get_mid(p->to, x, tot);
        siz[x] += siz[p->to];
        if( cmp(tmp, ret, tot) ) ret = tmp;
        if( cmp(p, ret, tot) ) ret = p;
    }
    return ret;
}
int ch[2][MAXN + 5], etot = 0;
bool dir[32][MAXN + 5]; int key[32][MAXN + 5];
int a[MAXN + 5], b[MAXN + 5], N, M;
void dfs(const int &k, int x, int f, bool t, const int &dep) {
    dir[dep][x] = t;
    if( !t ) key[dep][x] = a[G1.lca(k, x)];
    for(Graph::edge *p=G1.adj[x];p;p=p->nxt) {
        if( p->tag || p->to == f ) continue;
        dfs(k, p->to, x, t, dep);
    }
}
int divide(int x, int tot, int dep) {
    Graph::edge *m = get_mid(x, 0, tot);
    if( m == NULL ) return -1;
    m->tag = m->rev->tag = true;
    int tmp = (++etot);
    dfs(m->to, m->to, 0, G1.dep[m->to]>G1.dep[m->rev->to], dep);
    dfs(m->rev->to, m->rev->to, 0, G1.dep[m->to]<G1.dep[m->rev->to], dep);
    ch[G1.dep[m->to]>G1.dep[m->rev->to]][tmp] = divide(m->to, siz[m->to], dep + 1);
    ch[G1.dep[m->to]<G1.dep[m->rev->to]][tmp] = divide(m->rev->to, tot-siz[m->to], dep + 1);
    return tmp;
}
struct edge{
    int u, v, w;
    friend bool operator < (edge a, edge b) {
        return a.w < b.w;
    }
}e[MAXN + 5];
int fa[MAXN + 5];
int find(int x) {
    return fa[x] = (fa[x] == x) ? x : find(fa[x]) ;
}
struct node{
    node *ch[2];
    int cnt, sum;
}nd[32*MAXN + 5], *rt[MAXN + 5], *ncnt, *NIL;
node *new_tree(int nw, int x, int dep) {
    if( nw == -1 ) return NIL;
    node *p = (++ncnt);
    if( !dir[dep][x] ) p->sum = (p->sum + key[dep][x])%MOD;
    else p->cnt = (p->cnt + 1)%MOD;
    p->ch[dir[dep][x]] = new_tree(ch[dir[dep][x]][nw], x, dep + 1);
    p->ch[!dir[dep][x]] = NIL;
    return p;
}
int ans = 0, res = 0;
node *merge(node *rt1, node *rt2) {
    if( rt1 == NIL ) return rt2;
    if( rt2 == NIL ) return rt1;
    res = (res + 1LL*rt1->cnt*rt2->sum%MOD) % MOD;
    res = (res + 1LL*rt1->sum*rt2->cnt%MOD) % MOD;
    rt1->sum = (rt1->sum + rt2->sum)%MOD;
    rt1->cnt = (rt1->cnt + rt2->cnt)%MOD;
    rt1->ch[0] = merge(rt1->ch[0], rt2->ch[0]);
    rt1->ch[1] = merge(rt1->ch[1], rt2->ch[1]);
    return rt1;
}
void dfs2(int x, int f) {
    if( x <= N )
        rt[x] = new_tree(1, x, 0);
    else rt[x] = NIL;
    for(Graph::edge *p=G2.adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        dfs2(p->to, x);
    }
    res = 0;
    for(Graph::edge *p=G2.adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        rt[x] = merge(rt[x], rt[p->to]);
    }
    ans = (ans + 1LL*res*b[x]%MOD)%MOD;
}
void init() {
    for(int i=2;i<=2*MAXN;i++)
        lg[i] = lg[i>>1] + 1;
    ncnt = NIL = &nd[0];
    NIL->ch[0] = NIL->ch[1] = NIL;
    NIL->cnt = NIL->sum = 0;
}
int main() {
    init();
    scanf("%d%d", &N, &M);
    for(int i=1;i<=M;i++)
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    sort(e + 1, e + M + 1);
    for(int i=1;i<=N;i++)
        fa[i] = i;
    int cnt = N;
    for(int i=1;i<=M;i++) {
        int fu = find(e[i].u), fv = find(e[i].v);
        if( fu != fv ) {
            a[++cnt] = e[i].w; fa[cnt] = cnt;
            fa[fu] = fa[fv] = cnt;
            G1.addedge(cnt, fu), G1.addedge(cnt, fv);
        }
    }
    G1.build(find(1)); divide(1, cnt, 0);
    for(int i=1;i<=M;i++)
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    sort(e + 1, e + M + 1);
    for(int i=1;i<=N;i++)
        fa[i] = i;
    cnt = N;
    for(int i=1;i<=M;i++) {
        int fu = find(e[i].u), fv = find(e[i].v);
        if( fu != fv ) {
            b[++cnt] = e[i].w;
            fa[fu] = fa[fv] = fa[cnt] = cnt;
            G2.addedge(cnt, fu), G2.addedge(cnt, fv);
        }
    }
    dfs2(find(1), 0);
    printf("%d\n", ans);
}

@詳細@

RMQを求めてテーブルST LCA書き込み要求は、しかし、番目のテーブルには、二度の長さが必要ですが、私は二重の長さを使用する場合。

おすすめ

転載: www.cnblogs.com/Tiw-Air-OAO/p/11335060.html