#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
// ---- UI com flush para prompts ----
namespace ui {
inline void print(const std::string& msg){ std::cout << msg << std::flush; }
inline void println(const std::string& msg){ std::cout << msg << '\n' << std::flush; }
inline void pause(){ std::cout << "\nPressione ENTER para continuar..." << std::flush; std::string _; std::getline(std::cin, _); }
}
// ---- Estruturas ----
struct Player { int id; std::string nickname, team, role; int points, age; };
struct Node { Player d; Node *l, *r; int h; Node(const Player& p): d(p), l(nullptr), r(nullptr), h(1) {} };
// ---- AVL: utilitários ----
int height(Node* n){ return n ? n->h : 0; }
int balance(Node* n){ return n ? height(n->l) - height(n->r) : 0; }
void update(Node* n){ if(n) n->h = 1 + std::max(height(n->l), height(n->r)); }
Node* rotateRight(Node* y){ Node* x=y->l; Node* t=x->r; x->r=y; y->l=t; update(y); update(x); return x; }
Node* rotateLeft (Node* x){ Node* y=x->r; Node* t=y->l; y->l=x; x->r=t; update(x); update(y); return y; }
Node* rebalance(Node* n){
if(!n) return n; update(n); int b=balance(n);
if(b> 1 && balance(n->l)>=0) return rotateRight(n); // LL
if(b> 1 && balance(n->l)< 0){ n->l=rotateLeft(n->l); return rotateRight(n);} // LR
if(b<-1 && balance(n->r)<=0) return rotateLeft(n); // RR
if(b<-1 && balance(n->r)> 0){ n->r=rotateRight(n->r); return rotateLeft(n);} // RL
return n;
}
Node* minNode(Node* n){ while(n && n->l) n=n->l; return n; }
Node* insertNode(Node* n,const Player& p,bool& ok){
if(!n){ ok=true; return new Node(p); }
if(p.id<n->d.id) n->l=insertNode(n->l,p,ok);
else if(p.id>n->d.id) n->r=insertNode(n->r,p,ok);
else ok=false;
return rebalance(n);
}
Node* deleteNode(Node* n,int id,bool& ok){
if(!n){ ok=false; return nullptr; }
if(id<n->d.id) n->l=deleteNode(n->l,id,ok);
else if(id>n->d.id) n->r=deleteNode(n->r,id,ok);
else {
ok=true;
if(!n->l || !n->r){ Node* t=n->l?n->l:n->r; delete n; return t; }
Node* t=minNode(n->r); n->d=t->d; n->r=deleteNode(n->r,t->d.id,ok);
}
return rebalance(n);
}
// ---- Classe AVL ----
class AVL {
Node* root=nullptr;
void pre (Node* n) const { if(!n) return; showPlayer(n->d); pre(n->l); pre(n->r); }
void in (Node* n) const { if(!n) return; in(n->l); showPlayer(n->d); in(n->r); }
void post(Node* n) const { if(!n) return; post(n->l); post(n->r); showPlayer(n->d); }
Node* find(Node* n,int id) const {
if(!n) return nullptr; if(id==n->d.id) return n;
return id<n->d.id ? find(n->l,id) : find(n->r,id);
}
void collect(Node* n,std::vector<Player>& v) const {
if(!n) return; collect(n->l,v); v.push_back(n->d); collect(n->r,v);
}
void clearRec(Node* n){ if(!n) return; clearRec(n->l); clearRec(n->r); delete n; }
static bool cmpPlayers(const Player& A,const Player& B){
if(A.points!=B.points) return A.points>B.points; // desc por pontos
return A.nickname<B.nickname; // desempate por nick
}
public:
~AVL(){ clearRec(root); root=nullptr; }
bool insert(const Player& p){ bool ok=false; root=insertNode(root,p,ok); return ok; }
bool remove(int id){ bool ok=false; root=deleteNode(root,id,ok); return ok; }
const Player* searchId(int id) const { Node* n=find(root,id); return n?&n->d:nullptr; }
std::vector<Player> searchNick(const std::string& nick) const {
std::vector<Player> all,res; collect(root,all);
for(const auto& p:all) if(p.nickname==nick) res.push_back(p);
return res;
}
std::vector<Player> searchTeam(const std::string& team) const {
std::vector<Player> all,res; collect(root,all);
for(const auto& p:all) if(p.team==team) res.push_back(p);
return res;
}
void preOrder() const { pre(root); }
void inOrder() const { in(root); }
void postOrder() const { post(root); }
// Funções adicionais
size_t countTeam(const std::string& t) const { size_t c=0; std::vector<Player> a; collect(root,a); for(auto& p:a) if(p.team==t) ++c; return c; }
size_t countMinPts(int m) const { size_t c=0; std::vector<Player> a; collect(root,a); for(auto& p:a) if(p.points>=m) ++c; return c; }
bool existsNick(const std::string& n) const { std::vector<Player> a; collect(root,a); for(auto& p:a) if(p.nickname==n) return true; return false; }
size_t totalPlayers() const { std::vector<Player> a; collect(root,a); return a.size(); }
long long totalPoints() const { long long s=0; std::vector<Player> a; collect(root,a); for(const auto& p:a) s+=p.points; return s; }
double avgPoints() const { auto n=totalPlayers(); return n?double(totalPoints())/double(n):0.0; }
std::vector<Player> topN(size_t N) const {
std::vector<Player> a; collect(root,a);
std::sort(a.begin(),a.end(),cmpPlayers);
if(N>a.size()) N=a.size();
return std::vector<Player>(a.begin(),a.begin()+N);
}
static void showPlayer(const Player& p){
std::cout << "ID:" << p.id << " | Nick:" << p.nickname
<< " | Time:" << p.team << " | Funcao:" << p.role
<< " | Pontos:" << p.points << " | Idade:" << p.age << '\n';
}
}; // fecha a classe
// ---- Entrada guiada com prompts ----
int readInt(const std::string& label){
while(true){
ui::println("\n" + label + " (digite apenas inteiros, ex.: 10)");
ui::print("> ");
std::string s; if(!std::getline(std::cin,s)) return 0;
try{ size_t pos; int v=std::stoi(s,&pos); if(pos==s.size()) return v; } catch(...){}
ui::println("Entrada invalida. Tente novamente.");
}
}
std::string readStr(const std::string& label,const std::string& exemplo){
while(true){
ui::println("\n" + label + " (ex.: " + exemplo + ")");
ui::print("> ");
std::string s; std::getline(std::cin,s);
if(!s.empty()) return s;
ui::println("Campo nao pode ficar vazio. Tente novamente.");
}
}
// ---- Coleta de jogador ----
Player readPlayer(){
ui::println("\nCadastro de Jogador:");
ui::println("Exemplos: ID=101, Nick=LeoX, Time=Falcons, Funcao=Entry, Pontos=85, Idade=20");
Player p;
p.id = readInt("Insira ID (inteiro unico)");
p.nickname = readStr("Insira nome do jogador (nickname)","LeoX");
p.team = readStr("Insira nome do time","Falcons");
p.role = readStr("Insira funcao (Entry/Support/IGL/AWPer)","Entry");
p.points = readInt("Insira pontuacao (inteiro >= 0)");
while(p.points<0){ ui::println("Pontos nao podem ser negativos."); p.points=readInt("Insira pontuacao (>=0)"); }
p.age = readInt("Insira idade (inteiro >= 10)");
while(p.age<10){ ui::println("Idade minima recomendada: 10."); p.age=readInt("Insira idade (>=10)"); }
return p;
}
// ---- Dados de teste ----
void seed(AVL& t){
ui::println("\nCarregando dados de teste...");
std::vector<Player> v={
{10,"LeoX","Falcons","Entry",95,21},{4,"Tora","Falcons","Support",67,20},
{15,"Galaxy","Comets","IGL",88,23},{2,"Naomi","Vikings","AWPer",71,22},
{7,"Ragnar","Vikings","Entry",80,24},{20,"Zed","Titans","Support",60,19},
{13,"Aether","Comets","Entry",92,22},{1,"Mika","Titans","IGL",77,21},
{8,"Orion","Falcons","AWPer",85,23},{5,"Iris","Comets","Support",64,20}
};
size_t ok=0,dup=0; for(const auto& p:v){ if(t.insert(p)) ++ok; else ++dup; }
std::cout << "Sucesso: " << ok << " insercoes. Duplicadas: " << dup << ".\n" << std::flush;
}
// ---- Menu ----
void menu(){
ui::println("\n=== Campeonato de e-sports (AVL) ===");
ui::println("1- Inserir jogador (ID, nick, time, funcao, pontos, idade)");
ui::println("2- Remover por ID (informe ID inteiro do jogador)");
ui::println("3- Buscar por ID (ex.: 15)");
ui::println("4- Buscar por nickname (ex.: LeoX)");
ui::println("5- Listar por time (ex.: Falcons)");
ui::println("6- Pre-ordem (raiz-esq-dir)");
ui::println("7- Em-ordem (ordenado por ID)");
ui::println("8- Pos-ordem (esq-dir-raiz)");
ui::println("9- Contar jogadores do time (ex.: Comets)");
ui::println("10- Contar jogadores com pontos >= X (ex.: 80)");
ui::println("11- Verificar se existe nickname (ex.: Mika)");
ui::println("12- Total de jogadores");
ui::println("13- Soma total de pontos");
ui::println("14- Top N por pontos (ex.: N=5)");
ui::println("15- Media de pontos");
ui::println("16- Carregar dados de teste");
ui::println("0- Sair");
}
// ---- main ----
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(&std::cout); // garante flush automático
AVL t;
while(true){
menu();
int op = readInt("Escolha a opcao do menu");
switch(op){
case 1:{
Player p = readPlayer();
ui::println(t.insert(p) ? "Sucesso: Elemento inserido com sucesso." : "Erro: ID ja existente na arvore.");
ui::pause();
break;
}
case 2:{
int id = readInt("Remocao: insira o ID (inteiro), ex.: 10");
ui::println(t.remove(id) ? "Sucesso: Elemento removido com sucesso." : "Erro: Elemento nao encontrado na arvore.");
ui::pause();
break;
}
case 3:{
int id = readInt("Busca por ID: insira o ID (inteiro), ex.: 15");
if(const Player* q = t.searchId(id)) AVL::showPlayer(*q);
else ui::println("Erro: Elemento nao encontrado na arvore.");
ui::pause();
break;
}
case 4:{
std::string n = readStr("Busca por nickname: digite exatamente o apelido","LeoX");
auto v = t.searchNick(n);
if(v.empty()) ui::println("Erro: Elemento nao encontrado na arvore.");
else for(const auto& p : v) AVL::showPlayer(p);
ui::pause();
break;
}
case 5:{
std::string tm = readStr("Listar por time: informe o nome","Falcons");
auto v = t.searchTeam(tm);
if(v.empty()) ui::println("Nenhum jogador encontrado.");
else for(const auto& p : v) AVL::showPlayer(p);
ui::pause();
break;
}
case 6: ui::println("\nPre-ordem (raiz-esq-dir):"); t.preOrder(); ui::pause(); break;
case 7: ui::println("\nEm-ordem (ordenado por ID):"); t.inOrder(); ui::pause(); break;
case 8: ui::println("\nPos-ordem (esq-dir-raiz):"); t.postOrder(); ui::pause(); break;
case 9:{
std::string tm = readStr("Contagem por time: informe o nome","Comets");
std::cout << "Total de jogadores do time '" << tm << "': " << t.countTeam(tm) << '\n' << std::flush;
ui::pause();
break;
}
case 10:{
int x = readInt("Contagem por pontos: insira X (inteiro), ex.: 80");
std::cout << "Jogadores com pontos >= " << x << ": " << t.countMinPts(x) << '\n' << std::flush;
ui::pause();
break;
}
case 11:{
std::string n = readStr("Verificar nickname: digite exatamente o apelido","Mika");
ui::println(t.existsNick(n) ? "Existe jogador com esse nickname." : "Nao existe jogador com esse nickname.");
ui::pause();
break;
}
case 12: std::cout << "Total de jogadores: " << t.totalPlayers() << '\n' << std::flush; ui::pause(); break;
case 13: std::cout << "Soma total de pontos: " << t.totalPoints() << '\n' << std::flush; ui::pause(); break;
case 14:{
int N = readInt("Top N: insira quantos jogadores deseja ver (inteiro), ex.: 5");
size_t k = (N<=0 ? 0u : static_cast<size_t>(N));
auto top = t.topN(k);
if(top.empty()) ui::println("Arvore vazia ou N=0.");
else { std::cout << "Top " << N << ":\n" << std::flush; for(const auto& p : top) AVL::showPlayer(p); }
ui::pause();
break;
}
case 15: std::cout << "Media de pontos: " << std::fixed << std::setprecision(2) << t.avgPoints() << '\n' << std::flush; ui::pause(); break;
case 16: seed(t); ui::pause(); break;
case 0: ui::println("Saindo..."); return 0;
default: ui::println("Opcao invalida. Escolha um numero do menu."); ui::pause();
}
}
return 0;
}