RiseOJ는 solved.ac와 제휴 관계가 없습니다. 티어 아이콘 © solved.ac. solved.ac

Rush

C++만큼 빠르고, Python만큼 쉽게. — C++20으로 트랜스파일되는 경쟁 프로그래밍 언어.
선택하세요: Rush 어느 문제든 언어 선택기에서 골라 제출하세요.

Rush language reference

Fast as C++, easy as Python.

Rush is a small, statically-typed language for competitive programming. It
transpiles to C++20 and is compiled with g++ -O2, so a Rush solution runs at
the same speed as the equivalent hand-written C++ — but the syntax stays close
to pseudocode. This document is the complete language reference.

Run locally with the bundled compiler:

rush run   solution.rush          # compile and execute
rush build solution.rush -o sol   # compile to a native binary
rush transpile solution.rush      # print the generated C++ (to read/learn)

1. Program structure

Every program has an fn main(). Execution starts there.

fn main() {
    print("Hello, Rush!");
}

Comments are C-style:

// line comment
/* block
   comment */

Statements end with ;. Blocks use { }.


2. Types

Rush C++ Notes
ll long long 64-bit signed — the default integer
int int 32-bit signed
float double 64-bit floating point
bool bool true / false
str std::string text
void void function-return only
vec<T> std::vector<T> dynamic array; nests, e.g. vec<vec<ll>>

Mixing integer types widens to ll. Mixing an integer with a float produces a
float.


3. Literals

42            // ll
1000000007    // ll (64-bit, no overflow)
0xFF          // ll — hex literal (bit patterns, masks)
0x8000000000000000   // hex may use all 64 bits (top bit set -> negative ll)
3.14          // float
1e9           // float (exponent form)
1.5e-3        // float
true  false   // bool
"hi\n"        // str — escapes: \n \t \\ \" \0
[1, 2, 3]     // vec<ll> literal; [[1,2],[3,4]] nests to vec<vec<ll>>

A vector literal's element type is unified from its elements (numbers widen);
assigning it to a declared vec<T> adopts T. An empty [] is rejected —
declare the vector and push instead.


4. Variables

ll x = 5;              // declare + initialise
ll a, b, c;            // several at once (value-initialised to 0)
ll a = 1, b = 2;       // several with initialisers
float pi = 3.14159;
str name = "rush";
bool ok = true;

vec<ll> v(n);          // a vector of n zeros (constructor-style size)
vec<ll> w;             // an empty vector
vec<vec<ll>> grid(n);  // n empty rows

An uninitialised scalar starts at 0 / false / "" (predictable, unlike C++).


5. Operators

Arithmetic: + - * / %

Division follows the operand types, exactly like C++:

print(7 / 2);      // 3     — integer division (both operands integer)
print(7.0 / 2);    // 3.5   — real division (one operand is float)

% (modulo) is integer-only.

Bitwise & shift (integer-only): & | ^ ~ << >> >>>

ll m = (1 << n);           // 2^n
if ((mask & (1 << i)) != 0) { ... }   // is bit i set?
ll low = x & (-x);         // lowest set bit
ll hi = x >>> 1;           // UNSIGNED right shift: 0s fill from the top

>> is the arithmetic shift (keeps the sign); >>> is the logical shift
(fills with zeros) — the one you want when a 64-bit value is a bit pattern
(bitboards, masks, hashes) rather than a number. See also popcount, ctz,
clz, and umul in the standard library.

Comparison: == != < <= > >= (numbers, and str for == != < ...)

Logical: && || ! (operands must be bool)

Membership — in (yields bool):

if ("cad" in text) { ... }   // substring test on strings (KMP, fast)
if (x in seen) { ... }       // set<T> / uset<T> membership
if (key in m) { ... }        // map<K,V> / umap<K,V> — is it a key?
if (v in nums) { ... }       // vec<T> / arr<T> — linear scan

(for (x in v) is the separate range-for form, not this operator.)

Conditional (ternary): cond ? a : b

ll sign = x > 0 ? 1 : (x < 0 ? -1 : 0);
print(ok ? "YES" : "NO");

Assignment: = and compound += -= *= /= %= &= |= ^= <<= >>=
(+= also concatenates strings). Increment/decrement: ++ --.

Precedence matches C++. Rush fully parenthesises the generated C++, so what you
write is what you get.


6. Control flow

if (x > 0) {
    print("pos");
} else if (x < 0) {
    print("neg");
} else {
    print("zero");
}

while (n > 0) { n--; }

for (ll i = 0; i < n; i++) { print(i); }

for (x in v) { sum += x; }     // range-for over a vec/arr/deque/set/...

A condition may be a bool or a number (non-zero is true), so while (m--) and
if (flag) work as expected. break and continue behave as in C.


7. Functions

fn add(ll a, ll b) -> ll {
    return a + b;
}

fn greet(str who) {          // no '-> Type' means void
    print("hi", who);
}

Functions may call each other in any order and may recurse. A ref parameter
binds by reference, so writes are visible to the caller:

fn addone(ref ll x) { x += 1; }

fn main() {
    ll v = 41;
    addone(v);
    print(v);                // 42
}

8. Input & output

ll n;
input(n);                    // read one whitespace-separated value
ll a, b;
input(a, b);                 // read several at once

str line = read_line();      // read a WHOLE line (spaces included)

print(a, b);                 // values space-separated, then a newline
print("yes\n");              // a value ending in \n is not double-terminated
print();                     // just a newline
flush();                     // force stdout out, useful for interactive protocols

Files and time:

str text = read_file("weights.txt");   // whole file as text ("" if unreadable)
if (file_exists("weights.txt")) { ... }
ll t0 = clock_ms();                    // monotonic wall clock, milliseconds
// ... work ...
print(clock_ms() - t0, "ms");

9. Standard library

Everything below is built in — no imports. Types are written with their type
arguments, e.g. Fenwick<ll> bit(n).

Free functions

Call Meaning
min(a, b), max(a, b) smaller / larger (two numbers or two strings)
abs(x) absolute value
gcd(a, b), lcm(a, b) integer gcd / lcm
swap(a, b) swap two variables/elements
sort(v) sort a vec ascending
reverse(v) reverse a vec
unique(v) dedupe a sorted vec; returns new length
sum(v) total of a numeric vec (ll, or float)
len(v) / size(v) length of a vec (ll)
push(v, x) / pop(v) append / remove-last on a vec
compress(v) coordinate-compress a vec; returns #distinct
to_str(x) number/bool/str → str
to_int(s) strll
to_float(s) strfloat
popcount(x) number of set bits in the 64-bit pattern
ctz(x) count trailing zeros — index of the lowest set bit (64 if x == 0)
clz(x) count leading zeros (64 if x == 0)
umul(a, b) wrapping unsigned 64-bit multiply (mod 2^64; overflow-safe for hashes)
ord(s) character code of s's first byte (-1 if empty)
chr(n) one-character str from a character code
read_file(path) whole file as str ("" if unreadable)
file_exists(path) bool — can the file be opened?
clock_ms() monotonic wall clock in milliseconds (ll)
eof() bool — has stdin hit end-of-file?
stdin_ready() bool — is input (or EOF) waiting on stdin? (non-blocking)
v16_add(a, b, off, n) SIMD: a[j] += b[off+j] for j < n (both i16arr)
v16_sub(a, b, off, n) SIMD: a[j] -= b[off+j]
v16_copy(a, b, off, n) SIMD: a[j] = b[off+j]
v16_dotc(a, w, n) SIMD: Σ clamp(a[j],0,127)·w[j]ll (NNUE dot product)

The v16_* kernels run element-wise math over i16arr at 16–32 SIMD lanes
(the backend auto-vectorizes them; build with rush build --native for the
full width of the local CPU). i16arr values wrap at ±32768 — it is a
storage type for small numbers, built for accumulator math.
| prefix_function(s) | KMP prefix function → arr<ll> |
| z_function(s) | Z-function → arr<ll> |
| sqrt, floor, ceil, pow, hypot, sin, … | floating-point math (<cmath>) |

str methods

s.size(), s.substr(pos, len), s.find(t) (index or -1),
s.find_all(t) (arr<ll> of indices), s.contains(t) (bool),
s.split() (whitespace-tokenize → vec<str>). Also t in s tests substring.

s[i] yields the one-character str at position i (read-only — build a new
string to modify). Pair with ord/chr for character arithmetic:

str sq = "e4";
ll file = ord(sq[0]) - ord("a");   // 4
ll rank = ord(sq[1]) - ord("1");   // 3

Containers

Type Highlights
vec<T> dynamic array, indexable, iterable, sort/reverse/push/pop
arr<T> like vec but with method syntax: a.push(x), a.sort()
stack<T> push/pop/top/size/empty
queue<T> push/pop/front/back/size/empty
deque<T> push_back/push_front/pop_back/pop_front/front/back, indexable
pq<T> max-heap: push/pop/top
minpq<T> min-heap: push/pop/top
i16arr array of 16-bit ints: a(n), a[i], a.size() — pair with the v16_* SIMD kernels
set<T>/uset<T> ordered / hashed set: insert/erase/contains, iterable
map<T,U>/umap<T,U> ordered / hashed map: m[k], contains/erase
pair<T,U> fields .first, .second

Structures & algorithms

Type Constructor Operations
Fenwick<T> Fenwick<ll> f(n) f.add(i, v), f.sum(l, r), f.prefix(i)
SegTree<T> SegTree<ll> s(n) s[i]=v / s[i]+=v / s.set/add(i,v); from the same tree: s.sum(l,r), s.min(l,r), s.max(l,r), s[i]; walking: s.first_ge/first_le(l,x), s.last_ge/last_le(r,x), s.prefix_ge(x) → index or -1
LazySegTree<T> LazySegTree<ll> z(n) z.add(l,r,v), z.set(l,r,v), z.sum(l,r)
DSU DSU d(n) d.union(a,b), d.same(a,b), d.find(x), d.size(x), d.count()
Graph Graph g(n) g.add_edge/add_dir(u,v), g.deg(u), g.size()
WGraph WGraph g(n) g.add_edge/add_dir(u,v,w), g.dijkstra(src) -> arr<ll>
ModInt<MOD> (alias mint) mint<998244353> a = 5 + - * /, a.pow(e), a.inv(); prints as its value

All ranges are inclusive [l, r] and all indices are 0-based.


10. A complete example

Range-sum queries with a Fenwick tree:

fn main() {
    ll n, q;
    input(n, q);
    Fenwick<ll> bit(n);
    for (ll i = 0; i < n; i++) {
        ll x;
        input(x);
        bit.add(i, x);
    }
    for (ll k = 0; k < q; k++) {
        ll l, r;
        input(l, r);
        print(bit.sum(l, r));      // inclusive
    }
}

Geometry with float:

fn main() {
    float x1, y1, x2, y2;
    input(x1, y1, x2, y2);
    float dx = x2 - x1;
    float dy = y2 - y1;
    print(sqrt(dx * dx + dy * dy));   // any <cmath> function is available
}