Cod sursa(job #1726079)

Utilizator BrandonChris Luntraru Brandon Data 7 iulie 2016 11:19:14
Problema Struti Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.69 kb
#include <fstream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>

#define Pe pair <int, int>
#define mp make_pair
#define fi first
#define se second
using namespace std;

class InputReader {
public:
  InputReader() {}
  InputReader(const char *file_name) {
    input_file = fopen(file_name, "r");
    cursor = 0;
    fread(buffer, SIZE, 1, input_file);
  }
  inline InputReader &operator >>(int &n) {
    while (buffer[cursor] < '0' || buffer[cursor] > '9') {
      advance();
    }
    n = 0;
    while ('0' <= buffer[cursor] && buffer[cursor] <= '9') {
      n = n * 10 + buffer[cursor] - '0';
      advance();
    }
    return *this;
  }
private:
  FILE *input_file;
  static const int SIZE = 1 << 17;
  int cursor;
  char buffer[SIZE];
  inline void advance() {
    ++ cursor;
    if (cursor == SIZE) {
      cursor = 0;
      fread(buffer, SIZE, 1, input_file);
    }
  }
};

InputReader cin("divizori2.in");
ofstream cout("divizori2.out");

const int MaxN = 100005;

vector <int> G[MaxN], GrNode[MaxN], divisor, CurrSubtree[MaxN];
vector <int> MiniG0[MaxN];
vector <int> MiniG1[MaxN];
map <vector <int>, int> STMap;
int SubTree[MaxN], Group[MaxN], father[MaxN];
bool used[MaxN], used2[MaxN], used3[MaxN];
int n, GroupNr, Cnt, MaxLev, FarNode, MapTop, used3cnt, GrSz;
bool Ans, ret;

void DivInit(int n) {
  for (int i = 2; i < n; ++i) {
    if (n % i == 0) {
      divisor.push_back(i);
    }
  }
}

void Dfs2(int node, int CurrGr, int DivSz) {
  if (GrSz == DivSz) return;

  used3[node] = true;
  ++used3cnt;
  Group[node] = CurrGr;
  ++GrSz;

  for (auto nxt: G[node]) {
    if (used3[nxt]) continue;

    Dfs2(nxt, CurrGr, DivSz);
  }
}

void Dfs(int node, int DivSz, int parent, bool &Ans) {
  used[node] = true;

  for (auto nxt: G[node]) {
    if (used[nxt]) continue;

    Dfs(nxt, DivSz, node, Ans);
    SubTree[node] += SubTree[nxt];
    if (SubTree[node] > DivSz) {
      Ans = false;
    }
    else if (SubTree[node] == DivSz) {
      GrSz = 0;
      int switchused = false;
      if (!used3[parent]) {
        switchused = true;
        used3[parent] = true;
      }

      if (used3[node]) {
        continue;
      }

      Dfs2(node, ++GroupNr, DivSz);
      if (GrSz < DivSz) {
        Ans = false;
      }

      SubTree[node] = 0;
      if (switchused) {
        used3[parent] = false;
      }
    }
  }
}

inline void QueryInit() {
  Ans = true;
  for (int i = 1; i <= n; ++i) SubTree[i] = 1;
  GroupNr = 1;
  used3cnt = 0;
  memset(Group, 0, sizeof Group);
  memset(used, 0, sizeof used);
  memset(used3, 0, sizeof used3);
}

void GrNodeInit() {
  for (int i = 1; i <= GroupNr; ++i) {
    GrNode[Group[i]].push_back(i);
  }
}

void BuildGraph(vector <int> CurrG[], int CurrGroup) {
  for (auto it: GrNode[CurrGroup]) {
    if (Group[father[it]] == CurrGroup) {
      CurrG[it].push_back(father[it]);
      CurrG[father[it]].push_back(it);
    }
  }
}

void FindFarthest(vector <int> CurrG[], int node, int level = 1) {
  used2[node] = true;
  if (level > MaxLev) {
    MaxLev = level;
    FarNode = node;
  }

  for (auto nxt: CurrG[node]) {
    if (used2[node]) continue;

    FindFarthest(CurrG, nxt, level + 1);
  }
}

void CreateDiam(vector <int> CurrG[], vector <int> diam, int node) {
  used2[node] = true;
  if (node == FarNode) ret = true;

  for (auto nxt: CurrG[node]) {
    if (used2[node]) continue;

    CreateDiam(CurrG, diam, nxt);
    if (ret) {
      diam.push_back(nxt);
      return;
    }
  }
}

Pe FindRts(vector <int> CurrG[]) {
  MaxLev = 0;
  memset(used2, 0, sizeof used2);
  FindFarthest(CurrG, 1);

  int Rt = FarNode;
  MaxLev = 0;
  memset(used2, 0, sizeof used2);
  FindFarthest(CurrG, Rt);

  ret = false;
  vector <int> diam;
  memset(used2, 0, sizeof used2);
  CreateDiam(CurrG, diam, Rt);
  diam.push_back(Rt);

  if (diam.size() % 2 == 1) {
    return mp(diam.size() / 2 + 1, -1);
  }
  else {
    return mp(diam.size() / 2, diam.size() / 2 + 1);
  }
}

void CreateConfig(vector <int> CurrG[], int node) {
  used[node] = true;

  for (auto nxt: CurrG[node]) {
    if (used[nxt]) continue;

    CreateConfig(CurrG, nxt);
    CurrSubtree[node].push_back(STMap[CurrSubtree[nxt]]);
  }

  sort(CurrSubtree[node].begin(), CurrSubtree[node].end());
  if (!STMap[CurrSubtree[node]]) {
    STMap[CurrSubtree[node]] = ++MapTop;
  }
}

inline void IsomInit() {
  for (int i = 1; i <= n; ++i) CurrSubtree[i].clear();
  //STMap.clear();
  //MapTop = 0;
}

bool Isomorph(vector <int> G1[], vector <int> G2[]) {
  Pe ConfRt1, ConfRt2;
  STMap.clear();
  MapTop = 0;

  Pe Rt1 = FindRts(G1);
  IsomInit();
  CreateConfig(G1, Rt1.fi);
  ConfRt1.fi = STMap[CurrSubtree[Rt1.fi]];
  if (Rt1.se != -1) {
    IsomInit();
    CreateConfig(G1, Rt1.se);
    ConfRt1.se = STMap[CurrSubtree[Rt1.se]];
  }

  Pe Rt2 = FindRts(G2);
  IsomInit();
  CreateConfig(G2, Rt2.fi);
  ConfRt2.fi = STMap[CurrSubtree[Rt2.fi]];
  if (Rt2.se != -1) {
    IsomInit();
    CreateConfig(G2, Rt2.se);
    ConfRt2.se = STMap[CurrSubtree[Rt2.se]];
  }

  if (Rt1.se == -1 and Rt2.se == -1) {
    return ConfRt1.fi == ConfRt2.fi;
  }
  else if (Rt1.se == -1) {
    return ConfRt1.fi == ConfRt2.fi or ConfRt1.fi == ConfRt2.se;
  }
  else if (Rt2.se == -1) {
    return ConfRt1.fi == ConfRt2.fi or ConfRt2.se == ConfRt2.fi;
  }
  else {
    return ConfRt1.fi == ConfRt2.fi or ConfRt1.fi == ConfRt2.se or ConfRt1.se == ConfRt2.fi or ConfRt1.se == ConfRt2.se;
  }
}

inline vector <int> *MiniG(vector <int> MiniG0[], vector <int> MiniG1[], bool typ) {
  if (!typ) return MiniG0;
  return MiniG1;
}

bool Check() {
  int line = 0;
  //vector <int> MiniG0[MaxN];
  //vector <int> MiniG1[MaxN];
  for (int i = 0; i <= n; ++i) {
    MiniG0[i].clear();
    MiniG1[i].clear();
  }

  GrNodeInit();
  BuildGraph(MiniG(MiniG0, MiniG1, 0), 1);
  for (int i = 2; i <= GroupNr; ++i) {
    line = !line;
    BuildGraph(MiniG(MiniG0, MiniG1, line), i);

    //if (!Isomorph(MiniG(MiniG0, MiniG1, 0), MiniG(MiniG0, MiniG1, 1))) {
    vector <int> *G1 = MiniG(MiniG0, MiniG1, 0);
    vector <int> *G2 = MiniG(MiniG0, MiniG1, 1);
    if (!Isomorph(G1, G2)) {
      return false;
    }
  }
  return true;
}

int main() {
  cin >> n;
  Cnt = 2;
  if (n == 1) {
    cout << 1 << '\n';
    return 0;
  }

  for (int i = 1; i <= n - 1; ++i) {
    int a, b;
    cin >> a >> b;
    G[a].push_back(b);
    G[b].push_back(a);
  }

  DivInit(n);
  for (auto CurrDiv: divisor) {
    QueryInit();
    Dfs(1, CurrDiv, 0, Ans);
    if (!Ans or used3cnt < n) continue;
    Cnt += Check();
  }

  cout << Cnt << '\n';
  return 0;
}