HDU 5493 Enfileirar dois pontos mais a matriz de árvore

Título:

Há N pessoas em uma linha. Eles sabem sua altura e quantas pessoas na frente (ou atrás) são mais altas do que eles. Somos obrigados a determinar a ordem dessas N pessoas (se houver vários, produza aquele com a menor ordem lexicográfica)

Ideias:

Primeiro classificamos as N pessoas de pequeno a grande em termos de altura (é claro, de grande a pequena), percorremos as N pessoas e encontramos posições possíveis para elas. Como o K dado na pergunta pode ser a frente ou o verso, há dois casos, só precisamos tomar a menor posição, de modo a garantir que a resposta final seja a ordem lexicográfica mais baixa.

Então, como faço para encontrar o local? (O problema pode ser abstraído em N cenouras e colocá-las em N covas) No início, a localização de todos ainda não foi encontrada, o valor da matriz t [N] é 1, 1 significa que a cova ainda não foi usada, 0 significa que foi usada Acima. Suponha que N = 5, array t: 1 0 1 1 0, agora estamos procurando a posição da terceira pessoa, porque já sabemos K, podemos encontrar a menor posição onde o número do intervalo 1 à esquerda é maior que K (porque estamos Preencha os buracos de acordo com a altura de pequeno a grande, de modo que a altura restante deve ser maior ou igual à altura percorrida neste momento, e o 1 restante (na matriz t) é maior ou igual à altura atual, não importa como você o preencha). A determinação da posição pode ser obtida de forma eficiente na dicotomia e o cálculo rápido do número do intervalo 1 à esquerda pode ser obtido de forma eficiente com uma matriz de árvore . A complexidade final é n * logn * logn

#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll MAX_T=1e3+7;
const ll MAX_N=1e5+7;
ll T,N;
ll answer[MAX_N];
struct node{
    
    //按照高度从小到大排序 
	ll h,sum,id;
	bool operator<(const node &a)const {
    
    
		return h<a.h;	
	}
}hei[MAX_N];
ll t[MAX_N],t1[MAX_N];
ll lowbit(ll x){
    
    
	return x&(-x);
}
void add(ll *t,ll x,ll k){
    
    
	for(;x<=N;x+=lowbit(x)){
    
    
		t[x]+=k;
	}
	return ;
}
ll ask(ll *t,ll x){
    
    
	ll res=0;
	for(;x;x-=lowbit(x)){
    
    
		res+=t[x];
	}
	return res;
}
ll Find_pos(ll *t,ll sum){
    
    //二分找位置 
	ll i,j,L=1,R=N,mid,ans;
	while(L<=R){
    
    
		mid=L+(R-L)/2;
		ll tmp=ask(t,mid);
		if(tmp>=sum){
    
    
			ans=mid;
			R=mid-1;
		}
		else
		L=mid+1;
	}
	return ans;
}
int main()
{
    
    
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	ll i,j,k=0;
	scf("%lld",&T);
	while(T--){
    
    
		scf("%lld",&N);
		memset(t,0,sizeof(t));
		memset(t1,0,sizeof(t1));
		memset(answer,0,sizeof(answer));
		for(i=1;i<=N;i++){
    
    
			scf("%lld %lld",&hei[i].h,&hei[i].sum);
			hei[i].id=i;
			hei[i].sum++;//便于后面位置的查找
		}
		sort(hei+1,hei+N+1);
		bool flag=0;
		for(i=1;i<=N;i++){
    
    //判断不存在的情况
			if(hei[i].sum>N-i+1){
    
    //比他高的只有N-i+1人,而他却说有hei[i].sum个人比他高(hei[i].sum>N-i+1)
				flag=1;
				break;
			}
		}
		if(flag){
    
    
			prf("Case #%lld: impossible\n",++k);
			continue;
		}
		for(i=1;i<=N;i++){
    
    //初始化,起初位置都可放,用两个树状数组分别考虑前面后面两种情况 
			add(t,i,1);
			add(t1,i,1);
		}
		for(i=1;i<=N;i++){
    
    
			ll pos=Find_pos(t,hei[i].sum);
			ll pos1=N-Find_pos(t1,hei[i].sum)+1;//因为用树状数组求左边区间好求,那怎么办求右边区间呢(对应后边的情况)?我们只要将数组反转一下,把右区间转换成左边区间
			pos=min(pos,pos1);
			answer[pos]=hei[i].h;
			add(t,pos,-1);//去掉一个位置 
			add(t1,N-pos+1,-1);
		}
		prf("Case #%lld:",++k);
		for(i=1;i<=N;i++)
		prf(" %lld",answer[i]); 
		puts("");
	}
	return 0;
}

Acho que você gosta

Origin blog.csdn.net/weixin_43311695/article/details/108563823
Recomendado
Clasificación