Fenwick 树状数组上二分
其实应该叫倍增。
由于这篇文章中 \(\text{lowbit}\) 估计不少,所以一律用 \(low\)。
Acwing244. 谜一样的牛
给定一个长度 \(n\le 10^5\) 序列,求逆康托。
\(0\le a_i<i\)
若是 \(\log n\) 二分,再 \(\log n\) Fenwick,\(O(n\log^2 n)\) 要跑 600ms,数据加强一下就过不了。
若是 \(\log n\) 在线段树上二分,常数过大。
所以我们就请出了主题——树状数组上二分
原理是位置 \(x\) 存的是以 \(x\) 为右端点长度为 \(low(x)\) 区间信息。
由于 \(low(x)\) 都是 \(2\) 的幂,所以就是倍增的料!
不管了,好像代码更能让你懂。
/*
* Author: ShaoJia
* Last Modified time: 2022-09-26 19:47:51
* Motto: We'll be counting stars.
*/
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define For(i,j,k) for(int i=(j),i##_=(k);i<=i##_;i++)
#define Rof(i,j,k) for(int i=(j),i##_=(k);i>=i##_;i--)
const int N=1e5+5;
int n,a[N],c[N],b[N];
inline int low(int x){ return x&(-x); }
void add(int x,int y){ while(x<=n) c[x]+=y,x+=low(x); }
int jump(int x){//the last pos that presum<=x
int pos=0,sum=0,np;
Rof(i,20,0)
if((np=pos|(1<<i))<=n && sum+c[np]<=x)
sum+=c[np],pos=np;
return pos;
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);
cin>>n;
For(i,2,n) cin>>a[i];
For(i,1,n) c[i]=low(i);
Rof(i,n,1) b[i]=jump(a[i])+1,add(b[i],-1);
For(i,1,n) cout<<b[i]<<"\n";
return 0;}
P6619 [省选联考 2020 A/B 卷] 冰火战士
代码和题解都贺。
本文来自博客园,作者:ShaoJia,版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。