2019 ICPC Nanchang Regional K. Tree (heuristic merge on tree + dynamic open point line segment tree)

Title

Find 1 11 is the root ofnnOn a rooted tree of n points, an ordered pair of points(x, y) (x, y)satisfying the following conditions(x,y ) number (pointiiThe weight of i isvi v_ivi):

  1. One point is not an ancestor of another point
  2. v x + v y = v l c a ( x , y ) v_x+v_y=v_{lca(x,y)} vx+vand=vlca(x,y)
  3. x x xyyThe path length of y is less than or equal to the given valuekkk

n, k ≤ 1 e 5, 0 ≤ vi ≤ nn, k \ le 1e5, 0 \ le v_i \ le n n,k1e5,0vin

Problem-solving ideas:

Heuristic merging on the tree, first count the answers in the child tree of the lighter son, remove the traces of the lighter son after processing the lighter son, and then count the answers in the child tree of the heavier son. After the statistics are completed, the traces of the heavy son are retained, and the nodes of the light sons are traversed in turn to ask for answers, and the subtrees are merged after processing a lepton tree.
Specifically, for each weight xxx opens a line segment tree with a weight ofxxx , the depth is[l, r] [l,r][l,r ] How many points are in the range, and ask based on this.

The pit that I stepped on:
be up to k is understood to be k, and people are stupid
. If the upper limit of the calculated depth range exceeds n, n should be the upper limit instead of not asking (the sequelae of the last pit)
so English is very important

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

Guess you like

Origin blog.csdn.net/qq_43202683/article/details/104108315