BZOJ 4756 Promotion Counting(线段树合并 || dfs)

来源:互联网 发布:阿里云邮箱app 编辑:程序博客网 时间:2024/06/05 03:12

题意:给你一棵n个节点的树,根为1,问你每个节点,它的子树中有几个节点比它大。


思路:

有一个简单的方法是可以遍历一下这棵树,树状数组维护,对于每个点的答案为 子树节点个数-(遍历它后比它小的数的个数-遍历它前比它小的数的个数)。遍历完它的子树节点后把它插入树状数组。


还有一个方法是对于每个节点建立一颗权值线段树,然后自底向上合并,每次合并后就可以直接查找比它大的数的个数,因为此时的树中只有它子树的节点。


线段树合并代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 1e5+5;const int maxnode = 2e6+5;int tree[maxnode], lch[maxnode], rch[maxnode];int a[maxn], b[maxn], head[maxn], root[maxn], ans[maxn];int n, k, sz, seg;struct node{    int v, next;}edge[maxn];void init(){    k = 0, sz = 1, seg = 0;    memset(head, -1, sizeof(head));    memset(tree, 0, sizeof(tree));    memset(root, 0, sizeof(root));    memset(rch, 0, sizeof(rch));    memset(lch, 0, sizeof(lch));}void addEdge(int u, int v){    edge[k].v = v;    edge[k].next = head[u];    head[u] = k++;}void pushup(int rt){    tree[rt] = tree[lch[rt]]+tree[rch[rt]];}void build(int &rt, int l, int r, int pos){    rt = ++seg;    if(l == r)    {        tree[rt] = 1;        return ;    }    int mid = (l+r)/2;    if(pos <= mid) build(lch[rt], l, mid, pos);    else build(rch[rt], mid+1, r, pos);    pushup(rt);}int query(int rt, int l, int r, int i, int j){    if(i <= l && j >= r) return tree[rt];    int mid = (l+r)/2;    int res = 0;    if(i <= mid) res += query(lch[rt], l, mid, i, j);    if(j > mid) res += query(rch[rt], mid+1, r, i, j);    return res;}int merge(int x, int y){    if(!x) return y;    if(!y) return x;    lch[x] = merge(lch[x], lch[y]);    rch[x] = merge(rch[x], rch[y]);    pushup(x);    return x;}void dfs(int u){    for(int i = head[u]; ~i; i = edge[i].next)    {        int v = edge[i].v;        dfs(v);        root[u] = merge(root[u], root[v]);    }    ans[u] = query(root[u], 1, n, a[u]+1, n);}int main(void){    while(cin >> n)    {        init();        for(int i = 1; i <= n; i++)            scanf("%d", &a[i]), b[i] = a[i];        sort(b+1, b+1+n);        int t = unique(b+1, b+1+n)-b-1;        for(int i = 1; i <= n; i++)            a[i] = lower_bound(b+1, b+1+t, a[i])-b;        for(int i = 2; i <= n; i++)        {            int x;            scanf("%d", &x);            addEdge(x, i);        }        for(int i = 1; i <= n; i++)            build(root[i], 1, n, a[i]);        dfs(1);        for(int i = 1; i <= n; i++)            printf("%d\n", ans[i]);    }    return 0;}


dfs代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 1e5+5;const int maxm = 5e5+5;int ans[maxn], num[maxn], head[maxm], tree[maxn];int n, k, a[maxn], b[maxn];struct node{    int v, next;}edge[maxm];void init(){    k = 0;    memset(head, -1, sizeof(head));    memset(num, 0, sizeof(num));    memset(tree, 0, sizeof(tree));}void addEdge(int u, int v){    edge[k].v = v;    edge[k].next = head[u];    head[u] = k++;}int lowbit(int x){    return x&(-x);}void update(int pos, int val){    while(pos < maxn)    {        tree[pos] += val;        pos += lowbit(pos);    }}int query(int pos){    int res = 0;    while(pos)    {        res += tree[pos];        pos -= lowbit(pos);    }    return res;}void dfs(int u){    int pre = query(a[u]);    num[u] = 1;    for(int i = head[u]; ~i; i = edge[i].next)    {        int v = edge[i].v;        dfs(v);        num[u] += num[v];    }    int cur = query(a[u]);    ans[u] = num[u]-(cur-pre)-1;    update(a[u], 1);}int main(void){    while(cin >> n)    {        init();        for(int i = 1; i <= n; i++)            scanf("%d", &a[i]), b[i] = a[i];        sort(b+1, b+1+n);        int t = unique(b+1, b+1+n)-b-1;        for(int i = 1; i <= n; i++)            a[i] = lower_bound(b+1, b+1+t, a[i])-b;        for(int i = 2; i <= n; i++)        {            int x;            scanf("%d", &x);            addEdge(x, i);        }        dfs(1);        for(int i = 1; i <= n; i++)            printf("%d\n", ans[i]);    }    return 0;}


阅读全文
1 0
原创粉丝点击