#include using namespace std; #define FOR(i,a,b) for(int i=(a);i<(b);++i) #define REP(i,n) FOR(i,0,n) #define ALL(v) begin(v),end(v) #define fi first #define se second template inline bool chmax(A &a, B b) { if (a inline bool chmin(A &a, B b) { if (a>b) { a=b; return 1; } return 0; } using ll = long long; using pii = pair; constexpr ll INF = 1ll<<30; constexpr ll longINF = 1ll<<60; constexpr ll MOD = 1000000007; constexpr bool debug = 0; //---------------------------------// template struct SegmentTree { using value_type = T; using const_reference = const value_type &; using F = std::function; using size_type = std::size_t; SegmentTree(size_type n_, const F & f, const_reference id_elem) : f(f), id_elem(id_elem) { n = 1; while (n < n_) n <<= 1; node.resize(2 * n, id_elem); } size_type size() const noexcept { return n; } void set(size_type i, const_reference x) { assert(i < size()); node[i += size()] = x; update_(i); } void add(size_type i, const_reference x) { assert(i < size()); i += size(); node[i] = f(node[i], x); update_(i); } value_type fold(size_type l, size_type r) const { assert(l <= size() && r <= size()); value_type lv = id_elem, rv = id_elem; for (l += size(), r += size(); l < r; l >>= 1, r >>= 1) { if (l & 1) lv = f(lv, node[l++]); if (r & 1) rv = f(node[r - 1], rv); } return f(lv, rv); } size_type lower_bound(const_reference x) const { if (node[1] < x) return size(); size_type idx; value_type s = id_elem; for (idx = 1; idx < size();) { value_type nex = f(s, node[idx << 1]); if (nex < x) { idx = idx << 1 | 1; s = nex; } else idx = idx << 1; } return idx - n; } size_type upper_bound(const_reference x) const { if (node[1] <= x) return size(); size_type idx; value_type s = id_elem; for (idx = 1; idx < size();) { value_type nex = f(s, node[idx << 1]); if (nex <= x) { idx = idx << 1 | 1; s = nex; } else idx = idx << 1; } return idx - n; } private: size_type n; F f; value_type id_elem; std::vector node; void update_(size_type i) { assert(size() <= i && i < node.size()); while (i > 1) { i >>= 1; node[i] = f(node[i << 1], node[i << 1 | 1]); } } }; int main() { int N, Q; cin >> N >> Q; struct Data { double x, y; double deg; }; SegmentTree seg(N, [](auto && a, auto && b) { double c = cos(a.deg), s = sin(a.deg); Data res; res.deg = a.deg + b.deg; res.x = a.x + c * b.x - s * b.y; res.y = a.y + s * b.x + c * b.y; return res; }, Data{0, 0, 0} ); REP(i, N) seg.set(i, Data{1.0, 0, 0}); vector d(N, 1); vector rad(N); constexpr double PI = acos(-1.0); while (Q--) { int q, i; scanf("%d %d", &q, &i); --i; if (q == 0 || q == 1) { int x; scanf("%d", &x); if (q == 0) rad[i] = x * PI / 180; else d[i] = x; seg.set(i, Data{d[i] * cos(rad[i]), d[i] * sin(rad[i]), rad[i]}); } else { const Data & ans = seg.fold(0, i + 1); printf("%.18lf %.18lf\n", ans.x, ans.y); } } return 0; }