排序_纪中1386_bzoj4552_树状数组

Description

  你收到一项对数组进行排序的任务,数组中是1到N个一个排列。你突然想出以下一种特别的排序方法,分为以下N个阶段:
  •阶段1,把数字1通过每次交换相邻两个数移到位置1;
  •阶段2,用同样的方法把N移到位置N;
  •阶段3,把数字2移到位置2处;
  •阶段4,把数字N-1移到位置N-1处;
  •依此类推。
  换句话说,如果当前阶段为奇数,则把最小的未操作的数移到正确位置上,如果阶段为偶数,则把最大的未操作的数移到正确位置上。
  写一个程序,给出初始的排列情况,计算每一阶段交换的次数。

Input

  第一行包含一个整数N(1<=N<=100000),表示数组中元素的个数。
  接下来N行每行一个整数描述初始的排列情况。

Output

  输出每一阶段的交换次数。

Hint

[数据范围]

70%的数据N<=100

题解

对于每一个点用0和1标记是否排过序

因为每次交换只会置换未排序的项,于是问题就转变成了求向前或向后有多少数字还未排序,也就是1的个数

树状数组可以求区间和,线段树也行

硬是没想到正解,优美的暴力过70分。

代码/pas

var
  n:longint;
  a,f,t:array[0..100000]of int64;
procedure add(x,y:longint);
begin
  while x<=n do
  begin  
    f[x]:=f[x]+y;
    x:=x+(x and(-x));
  end;
end;
function get(x:longint):longint;  
begin
  get:=0;
  while x>0 do
  begin  
    get:=get+f[x];
    x:=x-(x and(-x));
  end;
end;
procedure init;
var
  i:longint;
begin
  readln(n);
  for i:=1 to n do
  begin
    read(a[i]);
    t[a[i]]:=i;
    add(i,1);
  end;
end;
procedure main;
var
  i,ans,g:longint;
begin
  for i:=1 to n do
  begin
    ans:=0;
    if i mod 2=1 then
    begin
      g:=(i+1)div 2;
      ans:=get(t[g]-1);
      add(t[g],-1);
    end
    else
    begin
      g:=n-(i-1)div 2;
      ans:=get(n)-get(t[g]);
      add(t[g],-1);
    end;
    writeln(ans);
  end;
end;
begin
  init;
  main;
end.

转载于:https://www.cnblogs.com/olahiuj/p/5781262.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值