#include #include #include #include #include #include #include #include #include #define debug_value(x) cerr << "line" << __LINE__ << ":<" << __func__ << ">:" << #x << "=" << x << endl; #define debug(x) cerr << "line" << __LINE__ << ":<" << __func__ << ">:" << x << endl; template inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } using namespace std; typedef long long ll; template struct LazySegmentTree { int n; T unit; S unit_lazy; vector node; vector lazy; vector lazyFlag; T (*calc)(T, T); S (*propagateLazy)(S, S); T (*merge)(S, T); LazySegmentTree(vector v, T UNIT, S UNIT_LAZY, T (*_calc)(T, T), S (*_propagateLazy)(S, S), T (*_merge)(S, T)) { int sz = (int)v.size(); unit = UNIT; unit_lazy = UNIT_LAZY; calc = _calc; propagateLazy = _propagateLazy; merge = _merge; n = 1; while(n < sz) n *= 2; node.resize(2*n-1, unit); lazy.resize(2*n-1, UNIT_LAZY); lazyFlag.resize(2*n-1, false); for(int i=0; i=0; i--) node[i] = calc(node[i*2+1], node[i*2+2]); } void lazyEvaluate(int k, int l, int r) { if(lazyFlag[k]) { node[k] = merge(lazy[k], node[k]); if(r - l > 1) { lazy[k*2+1] = propagateLazy(lazy[k*2+1], lazy[k]); lazy[k*2+2] = propagateLazy(lazy[k*2+2], lazy[k]); lazyFlag[k*2+1] = lazyFlag[k*2+2] = true; } lazyFlag[k] = false; lazy[k] = unit_lazy; } } //[a, b) //区間[a, b]への更新に対してはupdate(a, b+1, x)と呼ぶ void update(int a, int b, S x, int k=0, int l=0, int r=-1) { if(r < 0) r = n; lazyEvaluate(k, l, r); if(b <= l || r <= a) return; if(a <= l && r <= b) { lazy[k] = propagateLazy(lazy[k], x); lazyFlag[k] = true; lazyEvaluate(k, l, r); } else { update(a, b, x, 2*k+1, l, (l+r)/2); update(a, b, x, 2*k+2, (l+r)/2, r); node[k] = calc(node[2*k+1], node[2*k+2]); } } //[a, b) //区間[a, b]へのクエリに対してはquery(a, b+1)と呼ぶ T query(int a, int b, int k=0, int l=0, int r=-1) { if(r < 0) r = n; lazyEvaluate(k, l, r); if(b <= l || r <= a) return unit; if(a <= l && r <= b) return node[k]; T vl = query(a, b, 2*k+1, l, (l+r)/2); T vr = query(a, b, 2*k+2, (l+r)/2, r); return calc(vl, vr); } }; template struct matrix{ int n, m; vector> dat; matrix(int n_ = 0, int m_ = 0){ n = n_; m = m_; for(int i = 0; i < n; i++){ dat.push_back(vector(m)); } } vector& operator[](int x) { return dat[x]; } }; template void prod(matrix a, matrix b, matrix &ans){ assert(a.m == b.n); for(int i = 0; i < a.n; i++){ for(int j = 0; j < a.m; j++){ ans.dat[i][j] = 0; for(int k = 0; k < b.m; k++){ ans.dat[i][j] += (a.dat[i][k]*b.dat[k][j]); } } } } template matrix prod(matrix a, matrix b){ assert(a.m == b.n); matrix ans(a.n, b.m); for(int i = 0; i < a.n; i++){ for(int j = 0; j < a.m; j++){ ans.dat[i][j] = 0; for(int k = 0; k < b.n; k++){ ans.dat[i][j] += (a.dat[i][k]*b.dat[k][j]); } } } return ans; } template matrix add(matrix a, matrix b){ assert(a.n == b.n); assert(a.m == b.m); matrix ans(a.n, a.m); for(int i = 0; i < a.n; i++){ for(int j = 0; j < a.m; j++){ ans[i][j] = a[i][j]+b[i][j]; } } return ans; } template void copy_mat(matrix a, matrix &b){ assert(a.n == b.n); assert(a.m == b.m); for(int i = 0; i < a.n; i++){ for(int j = 0; j < a.m; j++){ b.dat[i][j] = a.dat[i][j]; } } } template void pow_mat(matrix a, ll n, matrix &ans){ matrix buf(a.n, a.n); matrix tmp(a.n, a.n); copy_mat(a, tmp); for(int i = 0; i < a.n; i++) { for(int j = 0; j < a.n; j++){ ans.dat[i][j] = 0; } ans.dat[i][i] = 1; } for(int i = 0; i <= 30; i++){ ll m = (ll)1 << i; if(m&n){ prod(tmp, ans, buf); copy_mat(buf, ans); } prod(tmp, tmp, buf); copy_mat(buf, tmp); } } template void print_mat(matrix a){ for(int i = 0; i < a.n; i++){ for(int j = 0; j < a.m; j++){ cout << a.dat[i][j] << ' '; } cout << endl; } } struct lazy{ double theta, d; }; matrix merge(lazy l, matrix node){ assert(node.n == 2); assert(node.m == 1); matrix ans(2, 1); ans[0][0] = l.d*(cos(l.theta)*node[0][0]-sin(l.theta)*node[1][0]); ans[1][0] = l.d*(sin(l.theta)*node[0][0]+cos(l.theta)*node[1][0]); return ans; } lazy propagate(lazy x, lazy y){ return (lazy){x.theta+y.theta, x.d*y.d}; } double d[100000], theta[100000]; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout << setprecision(10) << fixed; int n, q; cin >> n >> q; matrix unit_vec(2, 1), unit_mat(2, 2); unit_mat[0][0] = 1.0; unit_mat[1][1] = 1.0; vector> v(n); for(int i = 0; i < n; i++) { matrix m(2, 1); m[0][0] = 1.0; v[i] = m; d[i] = 1.0; } LazySegmentTree,lazy> sgt(v, unit_vec, (lazy){0.0, 1.0}, add, propagate, merge); for(int _ = 0; _ < q; _++){ int t, i; cin >> t >> i; i--; double x; if(t == 0){ cin >> x; x = x*M_PI/180.0; sgt.update(i, n, (lazy){x-theta[i], 1.0}); theta[i] = x; }else if(t == 1){ cin >> x; sgt.update(i, i+1, (lazy){0.0, x/d[i]}); d[i] = x; }else{ auto r = sgt.query(0, i+1); cout << r[0][0] << ' ' << r[1][0] << endl; } } }