2019 ICPC Nanchang Regional K. Tree(ツリーのヒューリスティックマージ+ダイナミックオープンポイントラインセグメントツリー)

題名

検索1 11nnのルートですn点のルートツリーで、次の条件を満たす点(x、y)(x、y)の順序付けられたペアx y 番号(ポイントiiiの重みはvi v_iです。v):

  1. ある点は別の点の祖先ではありません
  2. vx + vy = vlca(x、y)v_x + v_y = v_ {lca(x、y)} vX+vそして=vL C X Y
  3. xx xyyyのパスの長さは、指定された値kk以下ですk

n、k≤1 e 5、0≤vi≤nn、k \ le 1e5、0 \ le v_i \ le n n k1 e 5 0v

問題解決のアイデア:

ツリーでのヒューリスティックマージでは、最初に軽い息子の子ツリーで答えを数え、軽い息子を処理した後で軽い息子の痕跡を取り除き、次に重い息子の子ツリーで答えを数えます。統計が完了した後、重い息子のトレースが保持され、軽い息子のノードが順番にトラバースされて回答が求められ、サブツリーはレプトンツリーの処理後にマージされます。
具体的には、各重量xxxは、xxの重みで線分ツリーを開きますx、深さは[l、r] [l、r][ l r ]範囲内に何点あるか、これに基づいて尋ねます。

私が踏んだピット:
kまではkであると理解され、人々は愚か
です。計算された深度範囲の上限がnを超える場合、nは尋ねない(最後のピットの後遺症)ではなく上限でなければならない
ため、英語は非常に重要です

#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
using namespace std;
const int maxn = 1e5 + 50;
int n, k;
vector<int> g[maxn];
int val[maxn], son[maxn], dep[maxn], sz[maxn];
int T[maxn], lc[maxn*200], rc[maxn*200], tot = 0, sum[maxn*200];
void update(int &rt, int l, int r, int pos, int x){
    
    
    if(!rt) rt = ++tot;
    sum[rt] += x;
    if(l == r) return;
    if(pos <= mid) update(lc[rt], l, mid, pos, x);
    else update(rc[rt], mid+1, r, pos, x);
}
int qry(int rt, int l, int r, int L, int R){
    
    
    if(!rt) return 0;
    if(L <= l && r <= R) return sum[rt];
    int res = 0;
    if(L <= mid) res += qry(lc[rt], l, mid, L, R);
    if(R > mid) res += qry(rc[rt], mid+1, r, L, R);
    return res;
}
ll ans = 0;
void init(){
    
    
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i) scanf("%d", &val[i]);
    for(int i = 2; i <= n; ++i){
    
    int u; scanf("%d", &u); g[u].push_back(i);}
}
void dfs1(int u){
    
    
    sz[u] = 1;
    for(int i = 0; i < g[u].size(); ++i){
    
    
        int v = g[u][i];
        dep[v] = dep[u]+1;
        dfs1(v);  sz[u] += sz[v];
        if(sz[v] > sz[son[u]]) son[u] = v;
    }return;
}
void del(int u){
    
    
    update(T[val[u]], 1, n, dep[u], -1);
    for(int i = 0; i < g[u].size(); ++i) del(g[u][i]);
}
void qry(int u, int td, int tv){
    
    
    int d = k+2*td-dep[u];
    d = min(d, n);//Attention!!
    int t = 2*tv-val[u];
    if(d >= 1 && t >= 0 && t <= n)  ans = ans + 2LL*qry(T[t], 1, n, 1, d);
    for(int i = 0; i < g[u].size(); ++i) qry(g[u][i], td, tv);
}
void add(int u){
    
    
    update(T[val[u]], 1, n, dep[u], 1);
    for(int i = 0; i < g[u].size(); ++i) add(g[u][i]);
}
void dfs2(int u){
    
    

    for(int i = 0; i < g[u].size(); ++i){
    
    
        int v = g[u][i];
        if(v == son[u]) continue;
        dfs2(v);del(v);
    }
    if(son[u]) dfs2(son[u]);
    for(int i = 0; i < g[u].size(); ++i){
    
    
        int v = g[u][i];  if(v == son[u]) continue;
        qry(v, dep[u], val[u]);  add(v);
    }
    update(T[val[u]], 1, n, dep[u], 1);
}
int main()
{
    
    
    init();
    dep[1] = 1;
    dfs1(1);dfs2(1);
    cout<<ans<<endl;
}

おすすめ

転載: blog.csdn.net/qq_43202683/article/details/104108315