Codeforces Round #300(E,F 树状数组)

来源:互联网 发布:php file get content 编辑:程序博客网 时间:2024/05/16 04:59

F. A Heap of Heaps

Andrew skipped lessons on the subject 'Algorithms and Data Structures' for the entire term. When he came to the final test, the teacher decided to give him a difficult task as a punishment.

The teacher gave Andrew an array of n numbersa1, ..., an. After that he asked Andrew for eachk from 1 to n - 1 to build ak-ary heap on the array and count the number of elements for which the property of the minimum-rooted heap is violated, i.e. the value of an element is less than the value of its parent.

Andrew looked up on the Wikipedia that a k-ary heap is a rooted tree with vertices in elements of the array. If the elements of the array are indexed from 1 ton, then the children of element v are elements with indices k(v - 1) + 2,..., kv + 1 (if some of these elements lie outside the borders of the array, the corresponding children are absent). In anyk-ary heap every element except for the first one has exactly one parent; for the element 1 the parent is absent (this element is theroot of the heap). Denote p(v) as the number of the parent of the element with the numberv. Let's say that for a non-root element v the property of the heap is violated ifav < ap(v).

Help Andrew cope with the task!

Input

The first line contains a single integer n (2 ≤ n ≤ 2·105).

The second line contains n space-separated integersa1, ..., an ( - 109 ≤ ai ≤ 109).

Output

in a single line print n - 1 integers, separate the consecutive numbers with a single space — the number of elements for which the property of thek-ary heap is violated, for k = 1, 2, ...,n - 1.

Sample test(s)
Input
51 5 4 3 2
Output
3 2 1 0
Input
62 2 2 2 2 2
Output
0 0 0 0 0
Note

Pictures with the heaps for the first sample are given below; elements for which the property of the heap is violated are marked with red.

In the second sample all elements are equal, so the property holds for all pairs.


题意:给出n树,对着n个数按照下标建立k(1……n-1)叉堆(大根堆),问多少个节点不符合条件(节点的值小于父节点的值)

思路:按照每个节点的值从小到大排序,然后依次加入树状数组中,加入之前统计他的孩子节点有多少个比他小的,然后更新这个节点(注意更新的时候如果与排名下一个的值相等,则要等下一个查询完在更新,因为如果孩子节点的值小于父节点的值是满足条件的)。因为2叉树大约有n/2个节点有孩子,3叉树有n/3个节点有孩子,所以复杂度是nlognlogn的,满足题目条件

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=200010;int N;struct node{    int id;    int val;    bool operator<(const node &a)const    {        return val<a.val;    }}a[maxn];int tree[maxn];int ans[maxn];int getsum(int x){    int sum=0;    while(x)    {        sum+=tree[x];        x-=(x&(-x));    }    return sum;}void update(int x,int val){    while(x<=N)    {        tree[x]+=val;        x+=(x&(-x));    }}int main(){    while(scanf("%d",&N)!=EOF)    {        for(int i=1;i<=N;i++)        {            scanf("%d",&a[i].val);            a[i].id=i;        }        sort(a+1,a+1+N);        memset(tree,0,sizeof(tree));        memset(ans,0,sizeof(ans));        int cur=0;        for(int i=1;i<=N;i++)        {            for(int k=1;k<N;k++)            {                int lson=k*(a[i].id-1)+2;                if(lson>N)break;                int rson=k*a[i].id+1;                if(rson>N)rson=N;                int tmp=getsum(rson)-getsum(lson-1);                ans[k]+=tmp;            }            if(a[i].val!=a[i+1].val)            {                cur=i;                while(cur)                {                    update(a[cur].id,1);                    cur--;                    if(a[cur].val!=a[cur+1].val)break;                }            }        }        for(int i=1;i<N;i++)printf("%d ",ans[i]);        printf("\n");    }    return 0;}

E. Demiurges Play Again

Demiurges Shambambukli and Mazukta love to watch the games of ordinary people. Today, they noticed two men who play the following game.

There is a rooted tree on n nodes, m of which are leaves (a leaf is a nodes that does not have any children), edges of the tree are directed from parent to children. In the leaves of the tree integers from 1 tom are placed in such a way that each number appears exactly in one leaf.

Initially, the root of the tree contains a piece. Two players move this piece in turns, during a move a player moves the piece from its current nodes to one of its children; if the player can not make a move, the game ends immediately. Theresult of the game is the number placed in the leaf where a piece has completed its movement. The player who makes the first move tries to maximize the result of the game and the second player, on the contrary, tries to minimize the result. We can assume that both players move optimally well.

Demiurges are omnipotent, so before the game they can arbitrarily rearrange the numbers placed in the leaves. Shambambukli wants to rearrange numbers so that the result of the game when both players play optimally well is as large as possible, and Mazukta wants the result to be as small as possible. What will be the outcome of the game, if the numbers are rearranged by Shambambukli, and what will it be if the numbers are rearranged by Mazukta? Of course, the Demiurges choose the best possible option of arranging numbers.

Input

The first line contains a single integer n — the number of nodes in the tree (1 ≤ n ≤ 2·105).

Each of the next n - 1 lines contains two integersui andvi (1 ≤ ui, vi ≤ n) — the ends of the edge of the tree; the edge leads from node ui to nodevi. It is guaranteed that the described graph is a rooted tree, and the root is the node 1.

Output

Print two space-separated integers — the maximum possible and the minimum possible result of the game.

Sample test(s)
Input
51 21 32 42 5
Output
3 2
Input
61 21 33 41 55 6
Output
3 3
Note

Consider the first sample. The tree contains three leaves: 3, 4 and 5. If we put the maximum number 3 at node 3, then the first player moves there and the result will be 3. On the other hand, it is easy to see that for any rearrangement the first player can guarantee the result of at least 2.

In the second sample no matter what the arragment is the first player can go along the path that ends with a leaf with number 3.


下面思路参考别人的:

一棵树,有m个叶子,所有叶子标有号1~m。两个人轮流从根开始往下走,走到叶子结束。先手希望走到的叶子号尽可能大,后手希望尽可能小,两个人都是最优决策。问先手安排叶子号和后手安排叶子号时,走到的结果分别是什么。

        这题目出得好,我弄了很久才理解。首先假设树的所有叶子号我们都已经知道。定义MAX(u)是希望最大的人先手u为根的子树会走到的结果,MIN(u)是希望最小的人先手u为根的子树会走到的结果。vi是u的孩子,那么,MAX(u)就等于MIN(vi)中的最大值,MIN(u)就等于MAX(vi)中的最小值。

        但是,树的叶子号我们不知道(可以安排)。只考虑子树中每个叶子的相对大小,就是在子树中所有叶子的rank(从大到小依次1,2,3...)。记f(u)为希望最大的人先行动u子树得到的rank,g(u)为希望最小的人先行动u子树得到的rank。那么对于叶子有f(u)=g(u)=1,非叶子有f(u)=min(g(vi)),g(u)=sum(f(vi))。最后结果就是m-f(1)+1,g(1)(因为对称性)

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=200010;const int INF=1000000000;int N,M;vector<int> V[maxn];int f[maxn];int g[maxn];void dfs(int u){    int len=V[u].size();    if(len==0)    {        f[u]=g[u]=1;        M++;        return;    }    f[u]=INF,g[u]=0;    for(int i=0;i<len;i++)    {        int v=V[u][i];        dfs(v);        f[u]=min(f[u],g[v]);        g[u]+=f[v];    }}int main(){    while(scanf("%d",&N)!=EOF)    {        for(int i=0;i<=N;i++)V[i].clear();        M=0;        for(int i=1;i<N;i++)        {            int u,v;            scanf("%d%d",&u,&v);            V[u].push_back(v);        }        dfs(1);        printf("%d %d\n",M-f[1]+1,g[1]);    }    return 0;}



0 0