P3605 [USACO17JAN]Promotion Counting晋升者计数

题目:传送门

ps:方法较多,主席树,树状数组,线段树合并(感觉统计子树的某些信息很好用)

线段树合并:对每个节点建一颗线段树(实际上是一条长度为lg(n)的链),然后自底向上合并。

inline void upd(int &x, int y) { x > y && (x = y); }

const int N = 100005;

int n, tot, cnt;
int sum[20 * N], ls[20 * N], rs[20 * N], root[N], head[N], a[N], ans[N];

struct node { int to, next; } e[2 * N];

vector<int> id;

inline int getId(int x) { return lower_bound(Range(id), x) - id.begin(); }

void Inite() {
    cnt = tot = 0;
    mem(head, -1);
}

void addedge(int u, int v) {
    e[tot].to = v, e[tot].next = head[u], head[u] = tot++;
}

void Pushup(int rt) {
    sum[rt] = sum[ls[rt]] + sum[rs[rt]];
}

void Build(int l, int r, int &rt, int pos) {
    if (!rt) rt = ++cnt;
    if (l == r) {
        sum[rt]++;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) Build(l, mid, ls[rt], pos);
    else Build(mid + 1, r, rs[rt], pos);
    Pushup(rt);
}

int Merge(int x, int y) {
    if (!x || !y) return x ^ y;
    ls[x] = Merge(ls[x], ls[y]);
    rs[x] = Merge(rs[x], rs[y]);
    Pushup(x);
    return x;
}

int Query(int l, int r, int rt, int L, int R) {
    if (l > R || r < L || L > R) return 0;
    if (L <= l && r <= R) return sum[rt];
    int ans = 0;
    int mid = (l + r) >> 1;
    ans += Query(l, mid, ls[rt], L, R);
    ans += Query(mid + 1, r, rs[rt], L, R);
    return ans;
}

void DFS(int u) {
    for (int i = head[u]; ~i; i = e[i].next) {
        DFS(e[i].to);
        root[u] = Merge(root[u], root[e[i].to]);
    }
    ans[u] = Query(1, n, root[u], getId(a[u]) + 2, n);
}


int main()
{
    sc(n);
    Rep(i, 1, n) sc(a[i]), id.pb(a[i]);

    sort(Range(id));
    Rep(i, 1, n) Build(1, n, root[i], getId(a[i]) + 1);

    Inite();
    rep(i, 1, n) {
        int x;
        sc(x);
        addedge(x, i + 1);
    }

    DFS(1);
    Rep(i, 1, n) pr(ans[i]);
    return 0;
}
View Code

树状数组:借助差分的思想,答案 = 搜索完u的子树时比节点u权值大的节点 - 未搜索u的子树时比节点u权值大的节点。

const int N = 100005;

int n, cnt;
int a[N], bit[N], ans[N];

vector<int> id, G[N];

int getId(int x) { return lower_bound(Range(id), x) - id.begin(); }

int lowbit(int x) { return x & -x; }

void add(int pos) {
    for (int i = pos; i <= n; i += lowbit(i)) bit[i]++;
}

int sum(int pos) {
    int res = 0;
    for (int i = pos; i; i -= lowbit(i)) res += bit[i];
    return res;
}

void DFS(int u) {
    cnt++;
    add(getId(a[u]) + 1);
    int tp = cnt - sum(getId(a[u]) + 1);
    for (auto v : G[u]) DFS(v);
    ans[u] = cnt - sum(getId(a[u]) + 1) - tp;
}


int main()
{
    sc(n);
    Rep(i, 1, n) sc(a[i]), id.pb(a[i]);

    sort(Range(id));

    rep(i, 1, n) {
        int x;
        sc(x);
        G[x].pb(i + 1);
    }

    cnt = 0;
    DFS(1);

    Rep(i, 1, n) pr(ans[i]);
    return 0;
}
View Code

 

posted @ 2018-08-29 12:14  天之道,利而不害  阅读(245)  评论(0编辑  收藏  举报