计蒜之道 初赛第一场 百度科学家(困难) 【主席树优化建图】

传送门
题目大意: 太长了, 自己看.

思路: 主要是优化一个问题, 向区间连边, 那么就可以用线段树优化, 但是这个带修改点, 也就是要加入新的点, 所以就用主席树来优化建图, 每一个子节点就作为点本身, 然后其他的还是一样, 缩点, 找点权和最小叶子结点即可…
这道题目就作为主席树优化建图的入门题吧.

AC Coide

const int maxm = 1e5 +5;
// 强连通
int dfn[maxn], low[maxn], bel[maxn];
int dfs_id, scc_cnt;
vector<int>g[maxn]; // 原图以及新图
stack<int>st;
int in[maxn], n, m;
void tarjan(int u) {
    dfn[u] = low[u] = ++dfs_id;
    st.push(u);
    for(int i = 0 ; i < sz(g[u]) ; i++ ) {
        int v = g[u][i];
        if(!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!bel[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u]){
        scc_cnt++;
        while(1){
            int v = st.top();
            st.pop();
            bel[v] = scc_cnt;
            if(v == u) break;
        }
    }
}
void init() {
    dfs_id = scc_cnt = 0; Fill(in, 0);
    Fill(dfn, 0); Fill(bel, 0);
    for (int i = 1; i <= n; i++) g[i].clear();
}

// 主席树
struct Tree {
    int ls, rs, val; // 左右儿子的编号, 和维护的一个值.
}tree[maxn<<1];
int idx = 0, root[maxm], id[maxm];
int a[maxm];
int build(int l, int r) {
    int nod = ++idx;
    if (l == r) {
        id[l] = nod;
        tree[nod].val = a[l];
        return nod;
    }
    int mid = (l + r) >> 1;
    tree[nod].ls = build(l, mid);
    tree[nod].rs = build(mid+1, r);
    g[nod].pb(tree[nod].ls);
    g[nod].pb(tree[nod].rs);
    return nod;
}
int update(int pre, int l, int r, int pos, int val) {
    int nod = ++idx; tree[nod] = tree[pre];
    if (l == r) {
        id[l] = idx;
        tree[nod].val = val;
        return nod;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) tree[nod].ls = update(tree[pre].ls, l, mid, pos, val);
    else tree[nod].rs = update(tree[pre].rs, mid+1, r, pos, val);
    g[nod].pb(tree[nod].ls);
    g[nod].pb(tree[nod].rs);
    return nod;
}
void query(int id, int l, int r, int ql, int qr, int x) {
    if(qr < l || r < ql) return ;
    if(ql <= l && r <= qr){
        g[x].push_back(id);
        return ;
    }
    int mid = (l + r) >> 1;
    query(tree[id].ls, l, mid, ql, qr, x);
    query(tree[id].rs, mid + 1, r, ql, qr, x);
}
ll w[maxn];
void solve() {
    scanf("%d", &n); init();
    for (int i = 1 ; i <= n ; i ++) scanf("%d", a+i);
    root[0] = build(1, n); int pre = 0;
    scanf("%d", &m);
    while(m--) {
        int op, x, l, r;
        scanf("%d%d%d", &op, &x, &l);
        if (op) {
            scanf("%d", &r);
            query(root[pre], 1, n, l, r, id[x]);
        }
        else {
            root[pre+1] = update(root[pre], 1, n, x, l);
            ++pre;
        }
    }
    for (int i = 1 ; i <= idx ; i ++) {
        if (!dfn[i]) tarjan(i);
    }
    for (int i = 1 ; i <= idx ; i ++) {
        w[bel[i]] += tree[i].val;
        for (auto j : g[i]) {
            if (bel[i] != bel[j]) {
                in[bel[i]]++;
            }
        }
    }
    ll ans = INF;
    for (int i = 1 ; i<= scc_cnt ; i ++) {
        if (in[i]) continue;
        ans = min(ans, w[i]);
    }
    printf("%lld\n", ans);
}

你可能感兴趣的:(主席树)