hdu 5592 线段树 + 二分

来源:互联网 发布:java foreach能倒序 编辑:程序博客网 时间:2024/06/05 18:53
// hdu 5592 线段树 + 二分// 解题思路:// 设[1,n]区间逆序对数为f[i],p[i]为当前i位置的数字// 则x = f[i]-f[i-1]就是[1,i]区间比p[i]大的数.则i - x就是// 从[1,i]中这个数字排第几.二分这个数字得到答案为x,将x从// 线段树中删除.单点更新,区间查询.// 提示:线段树中存的是[1,n]各个数字的出现情况 #include <cstdio>#include <cstring>#include <algorithm>#define cls(x,a)memset(x,a,sizeof(x))using namespace std;const int MAX_N = 50000 + 8;int val[MAX_N];int a[MAX_N];bool vis[MAX_N];int N;struct IntervalTree{#define lson(x) (x << 1)#define rson(x) (x << 1 | 1)int sum[MAX_N << 2];void push_up(int ro){sum[ro] = sum[lson(ro)] + sum[rson(ro)];}void build(int ro,int L,int R){if (L == R){sum[ro] = 1;return ;}int M = (L + R) >> 1;build(lson(ro),L,M);build(rson(ro),M+1,R);push_up(ro);}void update(int ro,int L,int R,int pos){if (L == R){sum[ro] = 0;return ;}int M = (L + R) >> 1;if (pos <= M)update(lson(ro),L,M,pos);else update(rson(ro),M+1,R,pos);push_up(ro);}int query(int ro,int L,int R,int ql,int qr){if (ql <= L && R <= qr){return sum[ro];}int M = (L + R) >> 1;int ans = 0;if (ql <= M)ans += query(lson(ro),L,M,ql,qr);if (M < qr)ans += query(rson(ro),M+1,R,ql,qr);return ans;}}it;void input(){scanf("%d",&N);for (int i = 1;i <= N;i ++)scanf("%d",&val[i]);}void solve(){cls(vis,0);it.build(1,1,N);for (int i = N;i > 1;i --){int index = i - (val[i] - val[i-1]);int L = index;int R = N;int x;int M;while(L <= R){M = (L + R) >> 1;x = it.query(1,1,N,1,M);if (x == index && !vis[M])break;else if (x < index)L = M + 1;else R = M - 1;}a[i] = M;vis[M] = 1;it.update(1,1,N,M);}for (int i = 1;i <= N;i ++){if (!vis[i]){a[1] = i;break;}}for (int i = 1;i <= N;i ++){if (i != 1)printf(" ");printf("%d",a[i]);}puts("");}int main(){//freopen("1.in","r",stdin);int t;scanf("%d",&t);while(t--){input();solve();}}

0 0
原创粉丝点击