poj 2182 Lost Cows(模拟/线段树)

题目链接:http://poj.org/problem?id=2182

题意:

有一行牛身高从1到n,已知每个牛左面身高低于该牛的牛的个数,问这行牛的排列情况。(2≤n≤8000)

思路:

每次从后往前处理时从前往后找到余下数列的第pre[i]+1小元素。

Tips:

poj不支持<bits/stdc++.h>、基于范围的for循环、用变量定义数组大小。

暴力模拟:$O_{(n^2)}$

#include <iostream>
using namespace std;

const int M=10000;

int main()
{
    int n;cin>>n;
    int pre[M]={0};
    for(int i=1;i<n;i++) cin>>pre[i];

    int ans[M]={},vis[M]={};
    for(int i=n-1;i>=0;i--){
        int j=0,cnt=0;
        while(cnt<pre[i]){
            if(!vis[j]) ++cnt;
            ++j;
        }
        while(vis[j]) ++j;
        vis[j]=ans[i]=j+1;
    }

    for(int i=0;i<n;i++) cout<<ans[i]<<"\n";

    return 0;
}
View Code

线段树:$O_{(nlogn)}$

结构体实现:

#include <iostream>
#include <cstdio>
using namespace std;

const int M=10000;

struct{
    int l,r,len;
}tree[4*M];

int pre[M],ans[M];

void BuildTree(int left,int right,int u)
{
    tree[u].l=left;
    tree[u].r=right;
    tree[u].len=right-left+1;

    if(left==right) return;

    BuildTree(left,(left+right)>>1,u<<1);
    BuildTree(((left+right)>>1)+1,right,(u<<1)+1);
}

int query(int u,int num)
{
    --tree[u].len;

    if(tree[u].l==tree[u].r)
        return tree[u].l;

    if(tree[u<<1].len<num)
        return query((u<<1)+1,num-tree[u<<1].len);
    else
        return query(u<<1,num);
}

int main()
{
    int n;cin>>n;

    pre[1]=0;    
    for(int i=2;i<=n;i++) cin>>pre[i];
    
    BuildTree(1,n,1);

    for(int i=n;i>=1;i--)
        ans[i]=query(1,pre[i]+1);

    for(int i=1;i<=n;i++)
        cout<<ans[i]<<"\n";

    return 0;
}
View Code

完全二叉树实现:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

const int M=10000;

int pre[M],tree[4*M],ans[M];

void BuildTree(int n,int last_left)
{
    for(int i=last_left;i<last_left+n;i++)
        tree[i]=1;

    while(last_left!=1){
        for(int i=last_left/2;i<last_left;i++)
            tree[i]=tree[i*2]+tree[i*2+1];
        last_left/=2;
    }
}

int query(int u,int num,int last_left)
{
    --tree[u];

    if(tree[u]==0&&u>=last_left)
        return u;
    
    if(tree[u<<1]<num)
        return query((u<<1)+1,num-tree[u<<1],last_left);
    else
        return query(u<<1,num,last_left);
}

int main()
{
    int n;cin>>n;
    
    int last_left=1<<(int(log(n)/log(2))+1);
    pre[1]=0;
    for(int i=2;i<=n;i++) cin>>pre[i];
    
    BuildTree(n,last_left);
    
    for(int i=n;i>=1;i--)
        ans[i]=query(1,pre[i]+1,last_left)-last_left+1;
    
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<"\n";

    return 0;
}
View Code

三种方法的运行时长依次为:266MS、141MS、94MS。

posted @ 2020-03-29 21:47  Kanoon  阅读(121)  评论(0编辑  收藏  举报