POJ2182:Lost Cows
阿新 • • 發佈:2018-11-12
淺談線段樹和樹狀陣列:https://www.cnblogs.com/AKMer/p/9946944.html
題目傳送門:http://poj.org/problem?id=2182
線段樹,倒著確定每一個數字。因為最後一個是唯一的,得知最後一個是什麼之後倒數第二個就是唯一的了。每次詢問[\(1,n\)]中還沒有出現的數字第\(k\)大,直接線上段樹上找。如果左兒子裡可以用的數字個數大於\(k\),那麼就去左兒子裡面找,否則就去右兒子裡找第\(k\)-左兒子可用數字個數大的數。
時間複雜度:\(O(nlogn)\)
空間複雜度:\(O(n)\)
程式碼如下:
#include <cstdio> using namespace std; const int maxn=8005; int n; int a[maxn],ans[maxn]; int read() { int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; return x*f; } struct segment_tree { int tree[maxn<<2]; void updata(int p) { tree[p]=tree[p<<1]+tree[p<<1|1]; } void build(int p,int l,int r) { if(l==r) {tree[p]=1;return;}//初始每個數字都能用 int mid=(l+r)>>1; build(p<<1,l,mid);build(p<<1|1,mid+1,r); updata(p); } int query(int p,int l,int r,int rk) { if(l==r) { tree[p]=0; return l;//我把query和change寫一起了。 } int mid=(l+r)>>1,res; if(tree[p<<1]>=rk)res=query(p<<1,l,mid,rk); else res=query(p<<1|1,mid+1,r,rk-tree[p<<1]); updata(p);return res; } }T; int main() { n=read();T.build(1,1,n); for(int i=2;i<=n;i++) a[i]=read(); for(int i=n;i;i--) ans[i]=T.query(1,1,n,a[i]+1); for(int i=1;i<=n;i++) printf("%d\n",ans[i]);//倒著確定正著輸出 return 0; }