题目描述
N(2<=N<=8000)头奶牛在1…N范围内拥有不同的排名。到了排队吃晚饭的时候,他们没有按照排名的升序排队。
遗憾的是,FJ没有办法对它们进行排序。此外,他不太善于观察问题。他没有写下每头牛的排名,而是确定了一个相当愚蠢的统计数字:对于每一头牛,他知道排在那头牛前面的牛的数量,这些牛的排名比那头牛小。
根据这些数据,告诉FJ奶牛的确切顺序。
输入
第1行:单个整数N
第2…N行:这些N-1行描述了排在给定奶牛前面且排名小于该奶牛的奶牛数量。当然,没有一头牛排在第一头牛之前,所以她没有被列入名单。输入的第2行描述了前面的奶牛数量,其排名小于槽2中的奶牛;第3行描述了之前的奶牛数量,其品牌小于槽3中的奶牛;
输出
第1…N行:N行输出中的每一行都表示一头牛的排名。输出的第#1行表示第一头牛的排名;第2行显示第二头牛的排名;
样例输出
5
1
2
1
0
样例输入
2
4
5
3
1
线段树cpp
//#include<bits/stdc++.h>
#include<iostream>
using namespace std;
template <typename T> void debug(string s, T x) { cout << s << "=" << x << "\n"; }
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
const ll N = 1e4 + 5;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
struct {
ll l, r, len; // 用len存储这个区间的数字个数,即这个结点下牛的数量。
}tree[4 * N]; //这里开4倍大,因为线段树的空间需要。
ll pre[N], ans[N];
void BuildTree(ll left, ll right, ll u) { // 建树。
tree[u].l = left;
tree[u].r = right;
tree[u].len = right - left + 1; //更新结点u的值
if (left == right)return;
BuildTree(left, (left + right) >> 1, u << 1); //递归左子树。
BuildTree(((left + right) >> 1) + 1, right, (u << 1) + 1); //递归右子树。
}
ll query(ll u, ll num) { //查询+维护。所求值为当前区间的左起第num个元素。
tree[u].len--; //对访问到的区间维护len。即把这个结点上牛的数量减去一。
if (tree[u].l == tree[u].r)return tree[u].l;
//情况1:左子区间内牛的个数不够,则查询右子区间的左起第num - tree[u<<1].len个元素。
if (tree[u << 1].len < num)return query((u << 1) + 1, num - tree[u << 1].len);
//情况2:左子区间内牛的个数足够,则依旧查询左子区间的左起第num个元素。
if (tree[u << 1].len >= num)return query(u << 1, num);
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
ll n;
cin >> n;
for (ll i = 2; i <= n; i++)cin >> pre[i];
BuildTree(1, n, 1);
for (ll i = n; i >= 1; i--)ans[i] = query(1, pre[i] + 1);// 从后往前推断出每次最后一个数字。
for (ll i = 1; i <= n; i++)cout<<ans[i]<<"\n";
return 0;
}
数组数组cpp
#include<bits/stdc++.h>
using namespace std;
template <typename T> void debug(string s, T x) { cout << s << "=" << x << "\n"; }
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
const ll N = 1e4 + 5;
const ll MOD = 1e9 + 7;
const ll INF = 0x7fffffff;
const ll maxv = N;//区间最大值
ll Binary_Indexed_Tree[N];//树状数组
ll lowbit(ll x) {//数状数组lowbit()
return x & -x;
}
void update(ll index, ll val) {//在index位置加上val
while (index <= maxv) {
Binary_Indexed_Tree[index] += val;
index += lowbit(index);
}
}
ll sum(ll index) {//求Binary_Indexed_Tree[1 , index]的和
ll ans = 0;
while (index) {
ans += Binary_Indexed_Tree[index];
index -= lowbit(index);
}
return ans;
}
ll pre[N];
ll vis[N];
ll n;
ll solve(ll pos) {
ll k=0;
for (ll i = 1; i <= n; i++) {
if (!vis[i]) {
k++;
if (k == pos) {
vis[i] = 1;
return i;//返回第pos大的且未重复选过的数
}
}
}
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (ll i = 2; i <= n; i++)cin >> pre[i];
for (ll i = n; i >= 1; i--)update(i, solve(pre[i] + 1));//ans[i] = query(1, pre[i] + 1);// 从后往前推断出每次最后一个数字。
for (ll i = 1; i <= n; i++)cout<< sum(i)-sum(i-1)<<"\n";
return 0;
}