#pragma GCC optimize ("O3") #pragma GCC optimize ("unroll-loops") #pragma GCC target ("avx2") #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long int ll; typedef pair Pii; const ll mod = 1000000007; struct fenwick_tree { int n; vector data; fenwick_tree() { init(0); } fenwick_tree(int s) { init(s); } fenwick_tree(vector &v) { int s = v.size(); init(s); for (int i = 0; i < s; i++) add(i, v[i]); } void init(int s) { n = s; data = vector(s); } void add(int p, ll v) { p++; while (p <= n) { data[p-1] += v; p += p & -p; } } ll sum(int l, int r) { return sum(r) - sum(l); } ll sum(int r) { ll s = 0; while (r > 0) { s += data[r-1]; r -= r & -r; } return s; } }; struct euclid_lazy_segtree { int n; vector > data; vector > > lazy; vector lazyFlag; euclid_lazy_segtree() { init(1); } euclid_lazy_segtree(const int s) { init(s); } euclid_lazy_segtree(const vector > &v) { int s = v.size(); init(s); for (int i = 0; i < s; i++) { data[i+n-1][0] = v[i].first; data[i+n-1][1] = v[i].second; } } void init(const int s) { n = 1; while (n < s) n <<= 1; data = vector >(2*n-1, vector({0.0, 0.0, 1.0})); lazy = vector > >(2*n-1, vector >(3, vector(3))); for (int i = 0; i < 2*n-1; i++) { for (int j = 0; j < 3; j++) lazy[i][j][j] = 1.0; } lazyFlag = vector(2*n-1); } void apply_op(vector > &op, vector > &to) { evaluate_lazy(op, to); } void evaluate_lazy(vector > &op, vector > &to) { static vector > next(3, vector(3)); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { next[i][j] = 0.0; for (int k = 0; k < 3; k++) { next[i][j] += op[i][k] * to[k][j]; } } } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { to[i][j] = next[i][j]; } } } void evaluate_data(vector > &op, vector &to) { static vector next(3); for (int i = 0; i < 3; i++) { next[i] = 0.0; for (int k = 0; k < 3; k++) { next[i] += op[i][k] * to[k]; } } for (int i = 0; i < 3; i++) { to[i] = next[i]; } } void propagate(int p, int a, int b) { if (lazyFlag[p]) { if (b - a > 1) { evaluate_lazy(lazy[p], lazy[p*2+1]); evaluate_lazy(lazy[p], lazy[p*2+2]); lazyFlag[p*2+1] = true; lazyFlag[p*2+2] = true; } else { evaluate_data(lazy[p], data[p]); } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { lazy[p][i][j] = (i == j ? 1.0 : 0.0); } } lazyFlag[p] = false; } } void update(int l, int r, vector > op, int p = 0, int a = 0, int b = -1) { if (b < 0) b = n; // init // propagate lazy value propagate(p, a, b); if (r <= a || b <= l) return; // out of range if (l <= a && b <= r) { // fully covered evaluate_lazy(op, lazy[p]); lazyFlag[p] = true; propagate(p, a, b); } else { update(l, r, op, p*2+1, a, (a + b) / 2); // left update(l, r, op, p*2+2, (a + b) / 2, b); // right } return; } void translate(int l, int r, double x, double y) { vector > op({{1.0, 0.0, x}, {0.0, 1.0, y}, {0.0, 0.0, 1.0}}); update(l, r, op); } void rotate_with_pivot(int l, int r, double x, double y, double theta) { vector > op1({{1.0, 0.0, -x}, {0.0, 1.0, -y}, {0.0, 0.0, 1.0}}); vector > op2({{cos(theta), -sin(theta), 0.0}, {sin(theta), cos(theta), 0.0}, { 0.0, 0.0, 1.0}}); vector > op3({{1.0, 0.0, x}, {0.0, 1.0, y}, {0.0, 0.0, 1.0}}); vector > op({{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}); apply_op(op1, op); apply_op(op2, op); apply_op(op3, op); update(l, r, op); } pair query(int l, int r, int p = 0, int a = 0, int b = -1) { if (b < 0) b = n; // init if (r <= a || b <= l) return pair(0.0, 0.0); // out of range // propagate lazy value propagate(p, a, b); if (l <= a && b <= r) return pair(data[p][0] / data[p][2], data[p][1] / data[p][2]); // fully covered pair vl = query(l, r, p*2+1, a, (a + b) / 2); // left pair vr = query(l, r, p*2+2, (a + b) / 2, b); // right return pair(vl.first + vr.first, vl.second + vr.second); } }; int main() { cin.tie(0); ios::sync_with_stdio(false); int n, q; cin >> n >> q; vector > query(q, vector(3)); for (auto &x: query) { cin >> x[0] >> x[1]; if (x[0] != 2) cin >> x[2]; } vector > init_pos(n+1); for (int i = 0; i < n+1; i++) init_pos[i].first = 1.0 * i; euclid_lazy_segtree elst(init_pos); vector length(n, 1); fenwick_tree angle(n); vector > ans; for (auto &x: query) { if (x[0] == 0) { double delta = (double) (x[2] - angle.sum(x[1]-1, x[1])) * 3.141592653589793238462643383 / 180.0; auto pos = elst.query(x[1]-1, x[1]); elst.rotate_with_pivot(x[1], n+1, pos.first, pos.second, delta); angle.add(x[1]-1, x[2] - angle.sum(x[1]-1, x[1])); } else if (x[0] == 1) { double theta = (double) (angle.sum(0, x[1]) % 360) * 3.141592653589793238462643383 / 180.0; int delta = x[2] - length[x[1]-1]; elst.translate(x[1], n+1, (double) delta * cos(theta), (double) delta * sin(theta)); length[x[1]-1] = x[2]; } else if (x[0] == 2) { ans.push_back(elst.query(x[1], x[1]+1)); } } for (auto &x: ans) cout << fixed << setprecision(20) << x.first << " " << fixed << setprecision(20) << x.second << endl; return 0; }