UVA - 11525 Permutation (线段树)

题目连接:https://vjudge.net/problem/UVA-11525

思路:前几天刚做了一道题是给出一个排列,输出这个排列是按照字典序从小到大的第几个,答案是

                                                          s1 * (n - 1)! + s2 * (n - 2)! + ......sn * 0!

si表示排列第i个数右面比它小的数的个数,这道题是反了过来,给出了这个式子,求这个排列,首先我们可以把排列的第一个数给求出来,就是s1 + 1,之后我们就把这个数从1,2,3,4.....n这个排列中去掉,排列的第i个数就是1,2,3,4.....n这个排列的第si + 1个数,用线段树求一下就行了,然后单点更新删掉这个数

#include <bits/stdc++.h>
#define lson num << 1
#define rson num << 1 | 1
#define MAXN 500005
using namespace std;
struct node
{
    int l,r,sum;
}tree[MAXN << 2];
void build(int num,int l,int r)
{
	tree[num].l = l;
	tree[num].r = r;
	tree[num].sum = r - l + 1;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(lson,l,mid);
	build(rson,mid + 1,r);
	tree[num].sum = tree[lson].sum + tree[rson].sum;
}
int query(int num,int k)
{
	if(tree[num].l == tree[num].r) {
		tree[num].sum = 0;
		return tree[num].l;
	}
	int ans;
	if(tree[lson].sum >= k) ans = query(lson,k);
	else ans = query(rson,k - tree[lson].sum);
	tree[num].sum = tree[lson].sum + tree[rson].sum;
	return ans;
}
int main(void)
{
    int T,k,temp;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&k);
        build(1,1,k);
        for(int i = 1; i <= k; i++) {
         	   scanf("%d",&temp);
         	   if(i == 1) printf("%d",query(1,temp + 1));
         	   else printf(" %d",query(1,temp + 1));
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/81610990