結果
| 問題 | No.1020 Reverse |
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:10:02 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 144 ms / 2,000 ms |
| コード長 | 7,054 bytes |
| コンパイル時間 | 955 ms |
| コンパイル使用メモリ | 107,616 KB |
| 実行使用メモリ | 13,056 KB |
| 最終ジャッジ日時 | 2025-05-14 13:11:18 |
| 合計ジャッジ時間 | 3,080 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 15 |
ソースコード
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <random> // Required for std::mt19937 and std::random_device
#include <chrono> // For a better seed based on time
// Use Mersenne Twister for generating priorities. Provides better randomness than rand().
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
// Define the Node structure for the Treap
struct Node {
char key; // The character stored in this node
unsigned int priority; // Random priority for maintaining heap property
int size; // Size of the subtree rooted at this node (number of nodes)
bool reversed; // Lazy propagation flag for reversal operation
Node *l, *r; // Pointers to left and right children
// Constructor for creating a new node
Node(char k) : key(k), priority(rng()), size(1), reversed(false), l(nullptr), r(nullptr) {}
// Destructor (optional, generally omitted in competitive programming for speed)
// ~Node() { delete l; delete r; }
};
// Helper function to get the size of a subtree (handles nullptr case)
int get_size(Node* t) {
return t ? t->size : 0;
}
// Updates the size of node 't' based on the sizes of its children
void update_size(Node* t) {
if (t) {
t->size = get_size(t->l) + get_size(t->r) + 1;
}
}
// Pushes the lazy 'reversed' tag down to children
// This function must be called before accessing children of a node potentially marked as reversed
void push(Node* t) {
if (t && t->reversed) {
t->reversed = false; // Clear the flag on the current node
std::swap(t->l, t->r); // Swap children pointers physically reverses the order
// Propagate the reversed state to children by toggling their flags
if (t->l) t->l->reversed ^= true;
if (t->r) t->r->reversed ^= true;
}
}
// Splits the Treap 't' into two Treaps 'l' and 'r'.
// 'l' will contain the first 'k' elements of the sequence represented by 't'.
// 'r' will contain the remaining elements.
// 'k' is the count of elements for the left part.
void split(Node* t, Node*& l, Node*& r, int k) {
// Base case: If the treap is empty, both resulting treaps are empty.
if (!t) {
l = r = nullptr;
return;
}
push(t); // Process lazy tags before operating on the node or its children.
int left_size = get_size(t->l); // Get the size of the left subtree
// Determine if the split point is in the left or right subtree
if (k <= left_size) {
// Split point is within the left subtree.
// The current node 't' and its right subtree belong to the right part 'r'.
split(t->l, l, t->l, k); // Recursively split the left child. The resulting left part is 'l', right part updates t->l.
r = t;
} else {
// Split point is within the right subtree.
// The current node 't' and its left subtree belong to the left part 'l'.
// Adjust 'k' for the recursive call on the right subtree: need k - left_size - 1 elements from it.
split(t->r, t->r, r, k - left_size - 1);
l = t;
}
update_size(t); // Update the size of 't' after potential structural changes.
}
// Merges two Treaps 'l' and 'r' into a single Treap 't'.
// Assumes that all keys (implicitly, indices) in 'l' are less than all keys in 'r'.
void merge(Node*& t, Node* l, Node* r) {
push(l); // Process lazy tags before merging.
push(r);
// Base case: If one treap is empty, the result is the other treap.
if (!l || !r) {
t = l ? l : r;
} else if (l->priority > r->priority) {
// If 'l' has higher priority, it becomes the root.
// Recursively merge 'r' into the right subtree of 'l'.
merge(l->r, l->r, r);
t = l;
} else {
// If 'r' has higher priority (or equal), it becomes the root.
// Recursively merge 'l' into the left subtree of 'r'.
merge(r->l, l, r->l);
t = r;
}
update_size(t); // Update the size of the resulting root 't'.
}
// Performs an inorder traversal of the Treap 't' and appends characters to 'res' string.
// This reconstructs the string represented by the Treap.
void inorder_traversal(Node* t, std::string& res) {
if (!t) return;
push(t); // Ensure lazy tags are processed before visiting children.
inorder_traversal(t->l, res); // Visit left child
res += t->key; // Append current node's character
inorder_traversal(t->r, res); // Visit right child
}
// Optional: function to delete the treap nodes to free memory (usually skipped in CP)
void delete_treap(Node* t) {
if (!t) return;
delete_treap(t->l);
delete_treap(t->r);
delete t;
}
int main() {
// Optimize C++ standard streams for faster I/O.
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int N, K; // Read N (string length) and K (substring length for reversal)
std::cin >> N >> K;
std::string S; // Read the input string
std::cin >> S;
Node* root = nullptr; // Initialize root of the Treap as null
// Build the initial Treap from the input string S.
// Each character becomes a node, merged sequentially. O(N log N) build time.
for (char c : S) {
merge(root, root, new Node(c));
}
// Perform the sequence of reversal operations.
// Loop runs N-K+1 times, from i=1 to N-K+1.
for (int i = 1; i <= N - K + 1; ++i) {
Node *T1, *T2, *T3; // Temporary pointers for split parts
// The problem uses 1-based indexing [i, i+K-1].
// In 0-based indexing, this corresponds to [i-1, i+K-2].
// We need to extract the substring of length K starting at index i-1.
// Split the treap `root` into `T1` and `T2_T3`.
// `T1` contains the first `i-1` elements (indices 0 to i-2).
// `T2_T3` contains the rest (indices i-1 to N-1).
split(root, T1, T2, i - 1);
// Split `T2_T3` into `T2` and `T3`.
// `T2` contains the first `K` elements (indices i-1 to i+K-2). This is the target substring.
// `T3` contains the remaining elements (indices i+K-1 to N-1).
split(T2, T2, T3, K);
// Apply the reverse operation lazily to the extracted substring `T2`.
if (T2) {
T2->reversed ^= true; // Toggle the reversed flag. Actual reversal happens on push.
}
// Merge the three parts back together in the correct order.
merge(root, T1, T2); // Merge T1 and the (potentially reversed) T2.
merge(root, root, T3); // Merge the result with T3.
}
// Retrieve the final string by performing an inorder traversal of the modified Treap.
std::string final_S = "";
final_S.reserve(N); // Reserve capacity for efficiency.
inorder_traversal(root, final_S);
// Print the resulting string.
std::cout << final_S << std::endl;
// Optional cleanup (can be important for very large N or strict memory limits)
// delete_treap(root);
return 0;
}
qwewe