Submission #197986

#TimeUsernameProblemLanguageResultExecution timeMemory
197986model_codeLampice (COCI19_lampice)C++17
110 / 110
2111 ms17784 KiB
#include <bits/stdc++.h> using namespace std; struct Tree { vector<int> nodes; // original mapping vector<vector<int>> adj; void init(int num_nodes) { nodes.resize(num_nodes); adj.resize(num_nodes); } void clear() { nodes.clear(); adj.clear(); } }; class Decompositor { public: Decompositor(const Tree &tree) : tree_(tree), next_label_(0) { size_.resize(tree.nodes.size()); done_.resize(tree.nodes.size()); queue_.push(0); } // vraca sljedece dekomponirano stablo bool NextTree(Tree &decomposed_tree) { decomposed_tree.clear(); int node = GetQueuedNode(); if (node == -1) return false; CalculateSize(node); int centroid = FindCentroid(node, size_[node]); assert(centroid != -1); // build tree decomposed_tree.init(size_[node]); next_label_ = 0; BuildTree(decomposed_tree, centroid); // mark labels done_[centroid] = true; for (int y : tree_.adj[centroid]) queue_.push(y); return true; } private: const Tree &tree_; queue<int> queue_; vector<int> size_; vector<bool> done_; int next_label_; int GetQueuedNode() { for (; !queue_.empty(); queue_.pop()) { int x = queue_.front(); if (!done_[x]) return x; } return -1; } void CalculateSize(int x, int prev = -1) { size_[x] = 1; for (int y : tree_.adj[x]) { if (y == prev || done_[y]) continue; CalculateSize(y, x); size_[x] += size_[y]; } } int FindCentroid(int x, int tot_size, int prev = -1) { if (IsCentroid(x, tot_size)) return x; for (int y : tree_.adj[x]) { if (y == prev || done_[y]) continue; int q = FindCentroid(y, tot_size, x); if (q != -1) return q; } return -1; } bool IsCentroid(int x, int tot_size) { bool flag = false; if (2 * (tot_size - size_[x]) > tot_size) return false; for (int y : tree_.adj[x]) { if (done_[x] || size_[y] > size_[x]) continue; if (2 * size_[y] > tot_size) return false; } return true; } void BuildTree(Tree &target, int x, int prev = -1, int prev_label = -1) { int label = next_label_++; target.nodes[label] = x; if (prev_label != -1) target.adj[prev_label].push_back(label); for (int y : tree_.adj[x]) { if (y == prev || done_[y]) continue; BuildTree(target, y, x, label); } } }; const int MAXN = 100100; char input[MAXN]; class TreeSolver { public: TreeSolver(const Tree &tree): tree_(tree) { hash_down_.resize(tree.nodes.size()); hash_up_.resize(tree.nodes.size()); hash_set_.resize(tree.nodes.size()); stack_.reserve(tree.nodes.size()); } void Build(int x = 0, int dep = 0, long long hdown = 0, long long hup = 0) { const char c = input[tree_.nodes[x]]; hash_down_[x] = hdown * BASE + c; hash_up_[x] = hup + power_[dep] * c; for (int y : tree_.adj[x]) { Build(y, dep + 1, hash_down_[x], hash_up_[x]); } } int Solve() { return max(2 * Run(0) + 1, 2 * Run(1)); } int Run(int k) { int lo = 0, hi = (int)tree_.nodes.size(); while (lo < hi) { int mid = (lo + hi + 1) / 2; if (Check(mid, k)) lo = mid; else hi = mid - 1; } return lo; } static void InitPowers() { power_[0] = 1; for (int i = 1; i < MAXN; ++i) power_[i] = power_[i - 1] * BASE; } private: static const int BASE = 31337; static long long power_[MAXN]; Tree tree_; vector<long long> hash_down_; vector<long long> hash_up_; vector<unordered_set<long long>> hash_set_; vector<int> stack_; void SetHashes(int x, int dep) { hash_set_[dep].insert(hash_down_[x]); for (int y : tree_.adj[x]) SetHashes(y, dep + 1); } void ResetHashes() { for (auto &it : hash_set_) it.clear(); } // k 0 za neparno, 1 za parno bool Check(int len, int k) { // pazi na prazni string if (len == 0 && k == 1) return true; stack_.clear(); stack_.push_back(0); const int n = (int)tree_.adj[0].size(); for (int step = 0; step < 2; ++step) { ResetHashes(); for (int i = 0; i < n; ++i) { const int node = tree_.adj[0][i]; if (i > 0 && CheckSubtree(len, node, k)) return true; if (i + 1 != n) SetHashes(node, 1); } reverse(tree_.adj[0].begin(), tree_.adj[0].end()); } return false; } bool CheckSubtree(int len, int x, int k) { const int dep = (int)stack_.size(); stack_.push_back(x); bool ret = false; if (dep >= len) { if (CheckChain(len, dep, k)) { stack_.pop_back(); return true; } } for (int y : tree_.adj[x]) { if (CheckSubtree(len, y, k)) { stack_.pop_back(); return true; } } stack_.pop_back(); return false; } bool CheckChain(int len, int dep, int k) { int tot_len = 2 * len - k; if (dep >= tot_len) { long long hdown = hash_down_[stack_.back()]; long long hup = hash_up_[stack_.back()]; int i = dep - tot_len; if (i > 0) { hdown -= power_[tot_len + 1] * hash_down_[stack_[i - 1]]; hup -= hash_up_[stack_[i - 1]]; } return hdown * power_[i] == hup; } int tail = tot_len - dep; int head = dep - tail; if (hash_down_[stack_[head]] != hash_up_[stack_[head]]) return false; long long hdown = hash_down_[stack_.back()]; if (head > 0) hdown -= power_[tail + 1] * hash_down_[stack_[head - 1]]; return hash_set_[tail].find(hdown) != hash_set_[tail].end(); } }; long long TreeSolver::power_[MAXN]; void LoadTree(Tree &tree) { int n; scanf("%d", &n); scanf("%s", input); tree.init(n); for (int i = 0; i < n - 1; ++i) { int u, v; scanf("%d%d", &u, &v); u--; v--; tree.adj[u].push_back(v); tree.adj[v].push_back(u); } } int main(void) { TreeSolver::InitPowers(); Tree tree; LoadTree(tree); Decompositor decomp(tree); // border case :/ if (tree.nodes.size() == 2 && input[0] == input[1]) { printf("2\n"); return 0; } int ans = 0; for (Tree decomp_tree; decomp.NextTree(decomp_tree);) { TreeSolver solver(decomp_tree); solver.Build(); ans = max(ans, solver.Solve()); } printf("%d\n", ans); return 0; }

Compilation message (stderr)

lampice.cpp: In member function 'bool Decompositor::IsCentroid(int, int)':
lampice.cpp:84:10: warning: unused variable 'flag' [-Wunused-variable]
     bool flag = false;
          ^~~~
lampice.cpp: In member function 'bool TreeSolver::CheckSubtree(int, int, int)':
lampice.cpp:188:10: warning: unused variable 'ret' [-Wunused-variable]
     bool ret = false;
          ^~~
lampice.cpp: In function 'void LoadTree(Tree&)':
lampice.cpp:231:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d", &n);
   ~~~~~^~~~~~~~~~
lampice.cpp:232:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%s", input);
   ~~~~~^~~~~~~~~~~~~
lampice.cpp:236:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
     scanf("%d%d", &u, &v);
     ~~~~~^~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...