// >>> TEMPLATES #include using namespace std; using ll = long long; using ld = long double; using i32 = int32_t; using i64 = int64_t; using u32 = uint32_t; using u64 = uint64_t; #define int ll #define rep(i, n) for (int i = 0; i < (int)(n); i++) #define rep1(i, n) for (int i = 1; i <= (int)(n); i++) #define repR(i, n) for (int i = (int)(n)-1; i >= 0; i--) #define rep1R(i, n) for (int i = (int)(n); i >= 1; i--) #define loop(i, a, B) for (int i = a; i B; i++) #define loopR(i, a, B) for (int i = a; i B; i--) #define all(x) begin(x), end(x) #define allR(x) rbegin(x), rend(x) #define pb push_back #define eb emplace_back #define fst first #define snd second template auto constexpr inf_ = numeric_limits::max()/2-1; auto constexpr INF32 = inf_; auto constexpr INF64 = inf_; auto constexpr INF = inf_; #ifdef LOCAL #include "debug.hpp" #define oj_local(x, y) (y) #else #define dump(...) (void)(0) #define say(x) (void)(0) #define debug if (0) #define oj_local(x, y) (x) #endif template struct pque : priority_queue, Comp> { vector &data() { return this->c; } void clear() { this->c.clear(); } }; template using pque_max = pque>; template using pque_min = pque>; template ::value, int> = 0> ostream& operator<<(ostream& os, T const& a) { bool f = true; for (auto const& x : a) os << (f ? "" : " ") << x, f = false; return os; } template ::value, int> = 0> ostream& operator<<(ostream& os, const T (&a)[N]) { bool f = true; for (auto const& x : a) os << (f ? "" : " ") << x, f = false; return os; } template ())), class = typename enable_if::value>::type> istream& operator>>(istream& is, T &a) { for (auto& x : a) is >> x; return is; } template ostream& operator<<(ostream& os, pair const& p) { return os << p.first << " " << p.second; } template istream& operator>>(istream& is, pair& p) { return is >> p.first >> p.second; } struct IOSetup { IOSetup() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(15); } } iosetup; template struct FixPoint : private F { constexpr FixPoint(F&& f) : F(forward(f)) {} template constexpr auto operator()(T&&... x) const { return F::operator()(*this, forward(x)...); } }; struct MakeFixPoint { template constexpr auto operator|(F&& f) const { return FixPoint(forward(f)); } }; #define MFP MakeFixPoint()| #define def(name, ...) auto name = MFP [&](auto &&name, __VA_ARGS__) template struct vec_impl { using type = vector::type>; template static type make_v(size_t n, U&&... x) { return type(n, vec_impl::make_v(forward(x)...)); } }; template struct vec_impl { using type = T; static type make_v(T const& x = {}) { return x; } }; template using vec = typename vec_impl::type; template auto make_v(Args&&... args) { return vec_impl::make_v(forward(args)...); } template void quit(T const& x) { cout << x << endl; exit(0); } template constexpr bool chmin(T& x, U const& y) { if (x > (T)y) { x = (T)y; return true; } return false; } template constexpr bool chmax(T& x, U const& y) { if (x < (T)y) { x = (T)y; return true; } return false; } template constexpr auto sumof(It b, It e) { return accumulate(b, e, typename iterator_traits::value_type{}); } template int sz(T const& x) { return x.size(); } template int lbd(C const& v, T const& x) { return lower_bound(begin(v), end(v), x)-begin(v); } template int ubd(C const& v, T const& x) { return upper_bound(begin(v), end(v), x)-begin(v); } constexpr ll mod(ll x, ll m) { assert(m > 0); return (x %= m) < 0 ? x+m : x; } constexpr ll div_floor(ll x, ll y) { assert(y != 0); return x/y - ((x^y) < 0 and x%y); } constexpr ll div_ceil(ll x, ll y) { assert(y != 0); return x/y + ((x^y) > 0 and x%y); } constexpr int dx[] = { 1, 0, -1, 0, 1, -1, -1, 1 }; constexpr int dy[] = { 0, 1, 0, -1, 1, 1, -1, -1 }; constexpr int popcnt(ll x) { return __builtin_popcountll(x); } mt19937_64 seed_{random_device{}()}; template Int rand(Int a, Int b) { return uniform_int_distribution(a, b)(seed_); } i64 irand(i64 a, i64 b) { return rand(a, b); } // [a, b] u64 urand(u64 a, u64 b) { return rand(a, b); } // template void shuffle(It l, It r) { shuffle(l, r, seed_); } template V &operator--(V &v) { for (auto &x : v) --x; return v; } template V &operator++(V &v) { for (auto &x : v) ++x; return v; } bool next_product(vector &v, int m) { repR (i, v.size()) if (++v[i] < m) return true; else v[i] = 0; return false; } bool next_product(vector &v, vector const& s) { repR (i, v.size()) if (++v[i] < s[i]) return true; else v[i] = 0; return false; } template int sort_unique(vec &v) { sort(begin(v), end(v)); v.erase(unique(begin(v), end(v)), end(v)); return v.size(); } template auto prefix_sum(It l, It r) { vector s = { 0 }; while (l != r) s.emplace_back(s.back() + *l++); return s; } template auto suffix_sum(It l, It r) { vector s = { 0 }; while (l != r) s.emplace_back(*--r + s.back()); reverse(s.begin(), s.end()); return s; } template T pop(vector &a) { auto x = a.back(); a.pop_back(); return x; } template T pop(priority_queue &a) { auto x = a.top(); a.pop(); return x; } template T pop(queue &a) { auto x = a.front(); a.pop(); return x; } template T pop_front(deque &a) { auto x = a.front(); a.pop_front(); return x; } template T pop_back(deque &a) { auto x = a.back(); a.pop_back(); return x; } template T pop_front(set &a) { auto x = *a.begin(); a.erase(a.begin()); return x; } template T pop_back(set &a) { auto it = prev(a.end()); auto x = *it; a.erase(it); return x; } template T pop_front(multiset &a) { auto it = a.begin(); auto x = *it; a.erase(it); return x; } template T pop_back(multiset &a) { auto it = prev(a.end()); auto x = *it; a.erase(it); return x; } // <<< // >>> Point template constexpr bool equal(T x, T y) { return x == y; } template struct Point { T x, y; constexpr Point() : x(0), y(0) {} constexpr Point(T x, T y) : x(x), y(y) {} constexpr Point(complex const& z) : x(z.real()), y(z.imag()) {} constexpr pair to_pair() const { return {x, y}; } constexpr Point inv() const { return {x/norm(), -y/norm()}; } constexpr Point conj() const { return {x, -y}; } constexpr T norm() const { return x*x + y*y; } constexpr Point rot90(int n = 1) const { n %= 4; if (n < 0) n += 4; if (n == 1) return *this * Point(0, 1); if (n == 2) return *this * (-1); if (n == 3) return *this * Point(0, -1); return *this; } constexpr Point operator+() const { return *this; } constexpr Point operator-() const { return {-x, -y}; } constexpr Point operator+(Point const& p) const { return {x+p.x, y+p.y}; } constexpr Point operator-(Point const& p) const { return {x-p.x, y-p.y}; } constexpr Point operator*(Point const& p) const { return {x*p.x-y*p.y, x*p.y+y*p.x}; } constexpr Point operator/(Point const& p) const { return *this * p.conj() / p.norm(); } constexpr Point operator*(T const& a) const { return {a*x, a*y}; } constexpr Point operator/(T const& a) const { return {x/a, y/a}; } constexpr Point& operator+=(Point const& p) { return *this = *this + p; } constexpr Point& operator-=(Point const& p) { return *this = *this - p; } constexpr Point& operator*=(Point const& p) { return *this = *this * p; } constexpr Point& operator/=(Point const& p) { return *this = *this / p; } constexpr Point& operator*=(T const& a) { return *this = *this * a; } constexpr Point& operator/=(T const& a) { return *this = *this / a; } constexpr friend Point operator*(T const& a, Point const& p) { return p*a; } constexpr friend Point operator/(T const& a, Point const& p) { return Point(a)/p; } constexpr T dot(Point const& q) const { return x*q.x + y*q.y; } constexpr T cross(Point const& q) const { return x*q.y - y*q.x; } constexpr T dot(Point const& p, Point const& q) const { return (p-*this).dot(q-*this); } constexpr T cross(Point const& p, Point const& q) const { return (p-*this).cross(q-*this); } // constexpr bool operator==(Point const& q) const { return sgn(x-q.x) == 0 && sgn(y-q.y) == 0; } constexpr bool operator==(Point const& q) const { return equal(x, q.x) and equal(y, q.y); } constexpr bool operator!=(Point const& q) const { return !operator==(q); } constexpr friend Point conj(Point const& p) { return p.conj(); } constexpr friend T norm(Point const& p) { return p.x*p.x + p.y*p.y; } constexpr friend T dot(Point const& p, Point const& q) { return p.dot(q); } constexpr friend T cross(Point const& p, Point const& q) { return p.cross(q); } #ifdef LOCAL friend string to_s(Point const& p) { return to_s(p.to_pair()); } #endif friend istream& operator>>(istream& is, Point& p) { return is >> p.x >> p.y; } friend ostream& operator<<(ostream& os, Point const& p) { return os << p.x << " " << p.y; } }; // <<< template constexpr bool operator<(Point const& p, Point const& q) { return p.to_pair() < q.to_pair(); } //using P = Point; constexpr int sgn(int x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } using Real = long double; using P = Point; constexpr Real eps = 1e-10; constexpr int sgn(Real x) { return x > eps ? 1 : x < -eps ? -1 : 0; } constexpr Real pi = acos(-1.0L); constexpr Real to_rad(Real deg) { return Real(deg) * pi / 180; } constexpr Real to_deg(Real rad) { return rad * 180 / pi; } template constexpr T sq(T const& x) { return x*x; } template <> constexpr bool equal(Real x, Real y) { return sgn(x-y) == 0; } template constexpr Real abs(Point const& p) { return sqrt((Real)p.norm()); } constexpr Point normalize(Point const& p) { return p/abs(p); } // >>> segment tree template struct Segtree : Handler { using Value = typename Handler::Value; using Handler::unit_value; // () -> Value using Handler::merge; // (Value, Value) -> Value vector v; int n; Segtree() {} template Segtree(T&&... x) { init(forward(x)...); } template ()(0))> void init(int n, F gen) { assert(n >= 0); this->n = n; v.resize(2*n, unit_value()); for (int i = 0; i < n; i++) v[n+i] = gen(i); for (int i = n-1; i >= 1; i--) v[i] = merge(v[i<<1], v[i<<1|1]); } void init(int n) { init(n, [&](int) { return unit_value(); }); } void init(int n, Value const& x) { init(n, [&](int) { return x; }); } void init(vector const& v) { init(v.size(), [&](int i) { return v[i]; }); } int size() const { return n; } void set(int i, Value const& x) { assert(0 <= i); assert(i < size()); i += n; v[i] = x; while (i >>= 1) v[i] = merge(v[i<<1], v[i<<1|1]); } Value operator[](int i) const { return get(i); } Value get(int i) const { assert(0 <= i); assert(i < size()); return v[n + i]; } // [l, r) Value get(int l, int r) const { assert(0 <= l); assert(l <= r); assert(r <= size()); Value x = unit_value(), y = unit_value(); for (l += n, r += n; l < r; l >>= 1, r >>= 1) { if (l&1) x = merge(x, v[l++]); if (r&1) y = merge(v[--r], y); } return merge(x, y); } Value get_all() const { return get(0, size()); } template int max_right(int l, F f) { assert(0 <= l); assert(l <= size()); assert(f(unit_value())); l += n; const int r = size() << 1; Value x = unit_value(); while (true) { if (l == r) return size(); int k = __builtin_ctz(l | 1 << __lg(r - l)); auto y = merge(x, v[l >> k]); if (not f(y)) { l >>= k; break; } x = y, l += 1 << k; } while (l < size()) { auto y = merge(x, v[l <<= 1]); if (f(y)) x = y, l++; } return l - size(); } template int min_left(int r, F f) { assert(0 <= r); assert(r <= size()); assert(f(unit_value())); r += n; const int l = size(); Value x = unit_value(); while (true) { if (l == r) return 0; int k = __builtin_ctz(r | 1 << __lg(r - l)); auto y = merge(v[(r >> k) - 1], x); if (not f(y)) { r >>= k; --r; break; } x = y, r -= 1 << k; } while (r < size()) { r = r << 1 | 1; auto y = merge(v[r], x); if (f(y)) x = y, r--; } return r + 1 - size(); } vector dat() const { vector ret(size()); for (int i = 0; i < size(); i++) ret[i] = get(i); return ret; } }; // <<< // >>> matrix (array) // template // decltype(T::one()) semi_ring_one(signed) { return T::one(); } // template // constexpr T semi_ring_one(long) { return 1; } template struct Matrix { int n = N, m = M; array, N> a; Matrix() : a() {} Matrix(initializer_list> init) { size_t i = 0; for (auto ls : init) { size_t j = 0; for (auto const& x : ls) { a[i][j] = x; j++; } assert((int)j == m); i++; } assert((int)i == n); } array const& operator[](int i) const { assert(0 <= i); assert(i < n); return a[i]; } array & operator[](int i) { assert(0 <= i); assert(i < n); return a[i]; } bool operator==(Matrix const& x) const { if (n != x.n || m != x.m) return false; rep (i, n) rep (j, m) if (a[i][j] != x[i][j]) return false; return true; } bool operator!=(Matrix const& x) const { return !(*this == x); } Matrix operator+() const { return *this; } Matrix operator+(Matrix const& x) const { return Matrix(*this) += x; } Matrix& operator+=(Matrix const& x) { assert(n == x.n); assert(m == x.m); rep (i, n) rep (j, m) a[i][j] += x[i][j]; return *this; } template Matrix operator*(Matrix const& x) const { assert(m == x.n); Matrix ret; rep (i, n) rep (j, m) rep (k, x.m) ret[i][k] += a[i][j] * x[j][k]; return ret; } Matrix& operator*=(Matrix const& x) { auto res = (*this)*x; swap(a, res.a); return *this; } Matrix operator*(T const& c) const { return Matrix(*this) *= c; } Matrix& operator*=(T const& c) { rep (i, n) rep (j, m) a[i][j] *= c; return *this; } friend Matrix operator*(T const& c, Matrix const& x) { Matrix ret = x; rep (i, x.n) rep (j, x.m) ret[i][j] = c*x[i][j]; return ret; } static Matrix identity() { assert(N == M); Matrix ret; rep (i, N) ret[i][i] = P(1, 0); return ret; } Matrix pow(ll k) const { assert(n == m); assert(k >= 0); Matrix v = *this, r = Matrix::identity(); for (; k > 0; k >>= 1, v *= v) if (k&1) r *= v; return r; } #if 1 Matrix operator-() const { Matrix x = *this; rep (i, n) rep (j, m) x[i][j] = -x[i][j]; return x; } Matrix& operator-=(Matrix const& x) { assert(n == x.n); assert(m == x.m); rep (i, n) rep (j, m) a[i][j] -= x[i][j]; return *this; } Matrix operator-(Matrix const& x) const { return Matrix(*this) -= x; } Matrix& operator/=(T const& c) { rep (i, n) rep (j, m) a[i][j] /= c; return *this; } Matrix operator/(T const& c) const { return Matrix(*this) /= c; } #endif friend istream& operator>>(istream& is, Matrix& x) { rep (i, x.n) rep (j, x.m) is >> x[i][j]; return is; } #ifdef LOCAL friend string to_s(Matrix const& x) { string ret; rep (i, x.n) { ret += "\n("; rep (j, x.m) ret += " " + to_s(x[i][j]); ret += " )"; } return ret += "\n"; } #endif }; // <<< struct M { using Value = Matrix; static Value unit_value() { return Value::identity(); } static Value merge(Value const& x, Value const& y) { return y * x; } }; int32_t main() { int n; cin >> n; Segtree seg(n); rep (i, n) { Real p, q, r; cin >> p >> q >> r; P z(p, q); P rot = polar(Real(1), to_rad(r)); M::Value A = { { rot, z-z*rot }, { P(0, 0), P(1, 0) } }; seg.set(i, A); } int q; cin >> q; while (q--) { int l, r; cin >> l >> r; --l; Real x, y; cin >> x >> y; dump(l, r, x, y); auto A = seg.get(l, r); P p(x, y); p = A[0][0]*p + A[0][1]; cout << p.to_pair() << '\n'; } }