#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>
#include <climits>
#include <cstring>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
struct ACAutomaton {
struct Node {
Node* children[26];
Node* fail;
bool is_end;
int count;
Node() {
for (int i = 0; i < 26; ++i) {
children[i] = nullptr;
}
fail = nullptr;
is_end = false;
count = 0;
}
};
Node* root;
ACAutomaton() {
root = new Node();
}
void insert(const string& s) {
Node* curr = root;
for (char c : s) {
int idx = c - 'a';
if (!curr->children[idx]) {
curr->children[idx] = new Node();
}
curr = curr->children[idx];
}
curr->is_end = true;
curr->count++;
}
void build() {
queue<Node*> q;
for (int i = 0; i < 26; ++i) {
if (root->children[i]) {
root->children[i]->fail = root;
q.push(root->children[i]);
} else {
root->children[i] = root;
}
}
while (!q.empty()) {
Node* curr = q.front();
q.pop();
for (int i = 0; i < 26; ++i) {
if (curr->children[i]) {
Node* child = curr->children[i];
Node* f = curr->fail;
while (f != root && !f->children[i]) {
f = f->fail;
}
if (f->children[i] && f->children[i] != child) {
child->fail = f->children[i];
} else {
child->fail = root;
}
child->count += child->fail->count;
q.push(child);
} else {
curr->children[i] = curr->fail->children[i];
}
}
}
}
int query(const string& s) {
Node* curr = root;
int total = 0;
for (char c : s) {
int idx = c - 'a';
curr = curr->children[idx];
total += curr->count;
}
return total;
}
};
struct TreeDP {
struct Edge {
int to;
int weight;
Edge(int t, int w) : to(t), weight(w) {}
};
vector<vector<Edge>> adj;
vector<vector<int>> dp;
int n;
const int MAX_VALUE = 1e9;
TreeDP(int size) : n(size) {
adj.resize(n);
dp.resize(n, vector<int>(2, 0));
}
void addEdge(int u, int v, int w) {
adj[u].emplace_back(v, w);
adj[v].emplace_back(u, w);
}
void dfs(int u, int parent) {
dp[u][0] = 0;
dp[u][1] = 0;
for (const Edge& e : adj[u]) {
int v = e.to;
int w = e.weight;
if (v == parent) continue;
dfs(v, u);
dp[u][0] += max(dp[v][0], dp[v][1]);
dp[u][1] += dp[v][0] + w;
}
}
int solve() {
dfs(0, -1);
return max(dp[0][0], dp[0][1]);
}
};
template<typename T>
struct STTable {
vector<vector<T>> st;
vector<int> log_table;
int n;
int k;
STTable(const vector<T>& data) {
n = data.size();
if (n == 0) return;
log_table.resize(n + 1);
log_table[0] = 0;
log_table[1] = 0;
for (int i = 2; i <= n; ++i) {
log_table[i] = log_table[i / 2] + 1;
}
k = log_table[n] + 1;
st.resize(k, vector<T>(n));
for (int i = 0; i < n; ++i) {
st[0][i] = data[i];
}
for (int j = 1; j < k; ++j) {
for (int i = 0; i + (1 << j) <= n; ++i) {
st[j][i] = min(st[j-1][i], st[j-1][i + (1 << (j-1))]);
}
}
}
T query(int l, int r) {
if (l > r) swap(l, r);
int j = log_table[r - l + 1];
return min(st[j][l], st[j][r - (1 << j) + 1]);
}
};
struct MinCostFlow {
struct Edge {
int to;
int cap;
int cost;
int rev;
Edge(int t, int c, int co, int r) : to(t), cap(c), cost(co), rev(r) {}
};
vector<vector<Edge>> graph;
vector<int> h;
vector<int> dist;
vector<int> prev_v;
vector<int> prev_e;
int n;
const int INF = INT_MAX / 2;
MinCostFlow(int size) : n(size) {
graph.resize(n);
h.resize(n, 0);
dist.resize(n);
prev_v.resize(n);
prev_e.resize(n);
}
void add_edge(int from, int to, int cap, int cost) {
graph[from].emplace_back(to, cap, cost, graph[to].size());
graph[to].emplace_back(from, 0, -cost, graph[from].size() - 1);
}
int flow(int s, int t, int maxf) {
int res = 0;
fill(h.begin(), h.end(), 0);
while (maxf > 0) {
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
fill(dist.begin(), dist.end(), INF);
dist[s] = 0;
pq.emplace(0, s);
while (!pq.empty()) {
auto [d, v] = pq.top();
pq.pop();
if (dist[v] < d) continue;
for (int i = 0; i < graph[v].size(); ++i) {
Edge& e = graph[v][i];
if (e.cap > 0 && dist[e.to] > d + e.cost + h[v] - h[e.to]) {
dist[e.to] = d + e.cost + h[v] - h[e.to];
prev_v[e.to] = v;
prev_e[e.to] = i;
pq.emplace(dist[e.to], e.to);
}
}
}
if (dist[t] == INF) {
return -1;
}
for (int v = 0; v < n; ++v) {
h[v] += dist[v];
}
int d = maxf;
for (int v = t; v != s; v = prev_v[v]) {
d = min(d, graph[prev_v[v]][prev_e[v]].cap);
}
maxf -= d;
res += d * h[t];
for (int v = t; v != s; v = prev_v[v]) {
Edge& e = graph[prev_v[v]][prev_e[v]];
e.cap -= d;
graph[v][e.rev].cap += d;
}
}
return res;
}
};
vector<int> generate_data(int size) {
vector<int> data(size);
for (int i = 0; i < size; ++i) {
data[i] = rand() % 100;
}
return data;
}
int main() {
srand(time(0));
ACAutomaton ac;
ac.insert("Hello,");
ac.insert("World!");
ac.build();
string test_str = "helloworld";
int match_count = ac.query(test_str);
TreeDP tree(10);
tree.addEdge(0, 1, 5);
tree.addEdge(0, 2, 3);
tree.addEdge(1, 3, 2);
tree.addEdge(1, 4, 4);
tree.addEdge(2, 5, 6);
tree.addEdge(3, 6, 1);
tree.addEdge(4, 7, 7);
tree.addEdge(5, 8, 8);
tree.addEdge(5, 9, 9);
int tree_result = tree.solve();
vector<int> data = generate_data(20);
STTable<int> st(data);
int st_min = st.query(2, 15);
MinCostFlow mcf(5);
mcf.add_edge(0, 1, 10, 2);
mcf.add_edge(0, 2, 5, 3);
mcf.add_edge(1, 2, 3, 1);
mcf.add_edge(1, 3, 7, 4);
mcf.add_edge(2, 3, 6, 2);
mcf.add_edge(2, 4, 4, 5);
mcf.add_edge(3, 4, 8, 1);
int flow_cost = mcf.flow(0, 4, 10); printf("Hello, World!");
(void)match_count;
(void)tree_result;
(void)st_min;
(void)flow_cost;
return 0;
}