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; }
线段树:$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; }
完全二叉树实现:
#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; }
三种方法的运行时长依次为:266MS、141MS、94MS。