题意: 有n头牛, 标号为1~n, 它们不听话, 喝多了酒, 吃晚饭的时候没有按照序号排队, 告诉你此时队列里第2头牛到第n头牛它们前面序号比他们序号小的牛的数目, 让你求出这时排队的序列。
思路:咋看上去确实有点不像线段树, 但是倒着考虑下给你的那个数组, arr[i]表示的就是前i头牛, arr[i]的序号排第arr[i]+1名, 要逆着来, 每次都将找出来的牛拿出去就行。
#include<cstdio>
#include<cstring>
#include<iostream>
#define L(u) (u<<1)
#define R(u) (u<<1|1)
using namespace std;
const int N = 8010;
struct Node {
int l,r;
int num;
}node[N<<2];
int arr[N], flag, ans[N];
void pushUp(int u)
{
node[u].num = node[L(u)].num + node[R(u)].num;
}
void build(int u,int left,int right)
{
node[u].l = left,node[u].r = right;
if(node[u].l==node[u].r)
{
node[u].num = 1;
return;
}
int mid = (node[u].l+node[u].r)>>1;
build(L(u),left,mid);
build(R(u),mid+1,right);
pushUp(u);
}
void upDate(int u,int val)
{
if(node[u].l == node[u].r)
{
ans[flag] = node[u].l;
node[u].num = 0;
return;
}
if(node[L(u)].num >= val) upDate(L(u),val);
else upDate(R(u),val - node[L(u)].num);
pushUp(u);
}
int main(void)
{
int n;
scanf("%d",&n);
build(1,1,n);
flag = n;
for(int i=1; i<n; ++i)
{
scanf("%d",arr+i);
}
ans[1] = (n+1)*n/2;
for(int i=n-1; i>0; --i)
{
upDate(1,arr[i]+1);
ans[1] -= ans[flag];
--flag;
}
for(int i=1; i<=n; ++i)
printf("%d\n",ans[i]);
return 0;
}
本文探讨了一个涉及特定队列排列的问题,通过逆向思考和利用线段树结构,提出了一种高效的解决方案。重点在于理解问题背景,识别线段树的应用,并通过实例演示算法的具体实现。
646

被折叠的 条评论
为什么被折叠?



