#include <bits/stdc++.h> using namespace std; using ll=long long; //#define int ll #define rng(i,a,b) for(int i=int(a);i<int(b);i++) #define rep(i,b) rng(i,0,b) #define gnr(i,a,b) for(int i=int(b)-1;i>=int(a);i--) #define per(i,b) gnr(i,0,b) #define pb push_back #define eb emplace_back #define a first #define b second #define bg begin() #define ed end() #define all(x) x.bg,x.ed #define si(x) int(x.size()) #ifdef LOCAL #define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl #else #define dmp(x) void(0) #endif template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b;return true;}else return false;} template<class t,class u> bool chmin(t&a,u b){if(b<a){a=b;return true;}else return false;} template<class t> using vc=vector<t>; template<class t> using vvc=vc<vc<t>>; using pi=pair<int,int>; using vi=vc<int>; template<class t,class u> ostream& operator<<(ostream& os,const pair<t,u>& p){ return os<<"{"<<p.a<<","<<p.b<<"}"; } template<class t> ostream& operator<<(ostream& os,const vc<t>& v){ os<<"{"; for(auto e:v)os<<e<<","; return os<<"}"; } #define mp make_pair #define mt make_tuple #define one(x) memset(x,-1,sizeof(x)) #define zero(x) memset(x,0,sizeof(x)) #ifdef LOCAL void dmpr(ostream&os){os<<endl;} template<class T,class... Args> void dmpr(ostream&os,const T&t,const Args&... args){ os<<t<<" "; dmpr(os,args...); } #define dmp2(...) dmpr(cerr,__LINE__,##__VA_ARGS__) #else #define dmp2(...) void(0) #endif using uint=unsigned; using ull=unsigned long long; template<class t,size_t n> ostream& operator<<(ostream&os,const array<t,n>&a){ return os<<vc<t>(all(a)); } template<int i,class T> void print_tuple(ostream&,const T&){ } template<int i,class T,class H,class ...Args> void print_tuple(ostream&os,const T&t){ if(i)os<<","; os<<get<i>(t); print_tuple<i+1,T,Args...>(os,t); } template<class ...Args> ostream& operator<<(ostream&os,const tuple<Args...>&t){ os<<"{"; print_tuple<0,tuple<Args...>,Args...>(os,t); return os<<"}"; } template<class t> void print(t x,int suc=1){ cout<<x; if(suc==1) cout<<"\n"; if(suc==2) cout<<" "; } ll read(){ ll i; cin>>i; return i; } vi readvi(int n,int off=0){ vi v(n); rep(i,n)v[i]=read()+off; return v; } pi readpi(int off=0){ int a,b;cin>>a>>b; return pi(a+off,b+off); } template<class t,class u> void print(const pair<t,u>&p,int suc=1){ print(p.a,2); print(p.b,suc); } template<class T> void print(const vector<T>&v,int suc=1){ rep(i,v.size()) print(v[i],i==int(v.size())-1?suc:2); } string readString(){ string s; cin>>s; return s; } template<class T> T sq(const T& t){ return t*t; } //#define CAPITAL void yes(bool ex=true){ #ifdef CAPITAL cout<<"YES"<<"\n"; #else cout<<"Yes"<<"\n"; #endif if(ex)exit(0); #ifdef LOCAL cout.flush(); #endif } void no(bool ex=true){ #ifdef CAPITAL cout<<"NO"<<"\n"; #else cout<<"No"<<"\n"; #endif if(ex)exit(0); #ifdef LOCAL cout.flush(); #endif } void possible(bool ex=true){ #ifdef CAPITAL cout<<"POSSIBLE"<<"\n"; #else cout<<"Possible"<<"\n"; #endif if(ex)exit(0); #ifdef LOCAL cout.flush(); #endif } void impossible(bool ex=true){ #ifdef CAPITAL cout<<"IMPOSSIBLE"<<"\n"; #else cout<<"Impossible"<<"\n"; #endif if(ex)exit(0); #ifdef LOCAL cout.flush(); #endif } constexpr ll ten(int n){ return n==0?1:ten(n-1)*10; } const ll infLL=LLONG_MAX/3; #ifdef int const int inf=infLL; #else const int inf=INT_MAX/2-100; #endif int topbit(signed t){ return t==0?-1:31-__builtin_clz(t); } int topbit(ll t){ return t==0?-1:63-__builtin_clzll(t); } int botbit(signed a){ return a==0?32:__builtin_ctz(a); } int botbit(ll a){ return a==0?64:__builtin_ctzll(a); } int popcount(signed t){ return __builtin_popcount(t); } int popcount(ll t){ return __builtin_popcountll(t); } bool ispow2(int i){ return i&&(i&-i)==i; } ll mask(int i){ return (ll(1)<<i)-1; } bool inc(int a,int b,int c){ return a<=b&&b<=c; } template<class t> void mkuni(vc<t>&v){ sort(all(v)); v.erase(unique(all(v)),v.ed); } ll rand_int(ll l, ll r) { //[l, r] #ifdef LOCAL static mt19937_64 gen; #else static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count()); #endif return uniform_int_distribution<ll>(l, r)(gen); } template<class t> void myshuffle(vc<t>&a){ rep(i,si(a))swap(a[i],a[rand_int(0,i)]); } template<class t> int lwb(const vc<t>&v,const t&a){ return lower_bound(all(v),a)-v.bg; } vvc<int> readGraph(int n,int m){ vvc<int> g(n); rep(i,m){ int a,b; cin>>a>>b; //sc.read(a,b); a--;b--; g[a].pb(b); g[b].pb(a); } return g; } vvc<int> readTree(int n){ return readGraph(n,n-1); } //sz: size of the matching //mt[i]: matching mate of the vertex i //VERIFY: yosupo //NEERC2018B //Petrozavodsk 2019w Day1 A struct maxmatching{ struct E{int a,b;}; const vvc<int>&g; int n,sz; vi p,t,mt; vc<E> f; int non(int v){ return t[v]!=sz||p[v]==-1?v:(p[v]=non(p[v])); } void R(int a,int b){ int d=mt[a]; mt[a]=b; if(d==-1||mt[d]!=a)return; if(f[a].b==-1){ mt[d]=f[a].a; R(f[a].a,d); }else{ R(f[a].a,f[a].b); R(f[a].b,f[a].a); } } bool arg(int rt){ queue<int> q; t[rt]=sz; p[rt]=-1; f[rt]=E{-1,-1}; q.push(rt); while(!q.empty()){ int a=q.front();q.pop(); for(auto b:g[a]){ if(b==rt)continue; if(mt[b]==-1){ mt[b]=a; R(a,b); return true; } if(t[b]==sz){ int x=non(a),y=non(b); if(x==y)continue; int z=rt; while(x!=rt||y!=rt){ if(y!=rt)swap(x,y); if(f[x].a==a&&f[x].b==b){ z=x; break; } f[x]=E{a,b}; x=non(f[mt[x]].a); } for(auto v:{non(a),non(b)}){ while(v!=z){ t[v]=sz; p[v]=z; q.push(v); v=non(f[mt[v]].a); } } continue; } if(t[mt[b]]==sz)continue; f[b]=E{-1,-1}; t[mt[b]]=sz; p[mt[b]]=b; f[mt[b]]=E{a,-1}; q.push(mt[b]); } } return false; } maxmatching(const vvc<int>&gg):g(gg),n(g.size()),sz(0), p(n),t(n,-1),mt(n,-1),f(n){ rep(i,n)if(mt[i]==-1) sz+=arg(i); } //codechef HAMILG //res[i]=最大マッチングに必ず含まれるべき頂点なら 1, そうでないなら 0 vi need(){ rep(i,n)if(mt[i]==-1) arg(i); vi res(n); rep(i,n)res[i]=(mt[i]!=-1&&t[i]!=sz); return res; } }; bool adj(pi x,pi y){ auto [a,b]=x; auto [d,e]=y; int g=abs(a-d),h=abs(b-e); if(g==1&&h==2)return true; if(h==1&&g==2)return true; return false; } vi baka{640123342,149795075,435766641,962740521,655148792,415754176,376479654,870002679,720108329,159621518,11174811,387483131,378665771,561039471,331699185,126721473,443148615,932333129,537805256,560931851,365487476,533804022,740623840,763546631,538506276,874001638,94913828,147131095,947798556,252504454,124726188,728150503,340648925,846675740,753540696,201741433,457098100,242736752,101613178,179436008,422379147,716728797,130960454,582731547,879298814,327320790,601101480,712029853,666028075,}; int seed; using T=tuple<int,int,int>; vc<pi> dxy{}; vc<T> sub(int n){ int s=0; vvc<int> idx(n,vi(n,-1)); rep(i,n)rep(j,n){ if(pi(i,j)==pi(0,0))continue; if(pi(i,j)==pi(n-1,n-1))continue; idx[i][j]=s++; } vvc<int> g(s); rep(i,n)rep(j,n){ if(pi(i,j)==pi(0,0))continue; if(pi(i,j)==pi(n-1,n-1))continue; for(auto [x,y]:dxy){ x+=i; y+=j; if(inc(0,x,n-1)&&inc(0,y,n-1)){ if(pi(x,y)==pi(0,0))continue; if(pi(x,y)==pi(n-1,n-1))continue; g[idx[i][j]].pb(idx[x][y]); } } } //find a cycle vc<pi> lf; rep(step,n/2-1){ int x=n-1-step*2,y=step*2; lf.eb(x-2,y+1); lf.eb(x,y+2); lf.eb(x-1,y); if(step<n/2-2){ lf.eb(x-3,y+1); } } //dmp(lf); vi c{idx[n-1][0]}; for(auto [i,j]:lf)c.pb(idx[i][j]); c.pb(idx[1][n-2]); reverse(all(lf)); for(auto [i,j]:lf){ tie(i,j)=pi(n-1-j,n-1-i); //dmp2(i,j); c.pb(idx[i][j]); } //dmp(idx); rep(i,si(c)){ int j=c[(i+1)%si(c)]; //dmp2(i,j); assert(find(all(g[c[i]]),j)!=g[c[i]].ed); } vc<pi> pos; rep(i,n)rep(j,n)if(idx[i][j]!=-1)pos.eb(i,j); while(1){ //int seed=rand_int(0,ten(9)); mt19937 rnd(seed); vc<bool> vis(s); for(auto i:c)vis[i]=true; vc<T> ans; int cur=0; rep(i,si(c)){ int v=c[i]; vi tmp; while(1){ vis[v]=true; tmp.pb(v); int mn=inf; vi buf; for(auto j:g[v])if(!vis[j]){ int cnt=0; for(auto k:g[j])if(!vis[k])cnt++; if(mn>cnt){ buf.clear(); mn=cnt; } if(mn==cnt){ buf.pb(j); } } if(buf.empty())break; v=buf[rnd()%si(buf)]; } for(auto w:tmp){ ans.eb(pos[w].a,pos[w].b,cur); } cur^=1; reverse(all(tmp)); for(auto w:tmp){ ans.eb(pos[w].a,pos[w].b,cur); } } if(si(ans)==2*n*n-4){ baka.pb(seed); return ans; } } } bool adj(T x,T y){ auto [a,b,c]=x; auto [d,e,f]=y; if(c!=f)return pi(a,b)==pi(d,e); int g=abs(a-d),h=abs(b-e); if(g==1&&h==2)return true; if(h==1&&g==2)return true; return false; } void check(int n,vc<T> z){ assert(si(z)==2*n*n-4); for(auto [a,b,c]:z){ assert(inc(0,a,n-1)); assert(inc(0,b,n-1)); assert(inc(0,c,1)); assert(pi(a,b)!=pi(0,0)); assert(pi(a,b)!=pi(n-1,n-1)); } rep(i,si(z)){ assert(adj(z[i],z[(i+1)%si(z)])); } mkuni(z); assert(si(z)==2*n*n-4); } void slv(){ } signed main(){ cin.tie(0); ios::sync_with_stdio(0); cout<<fixed<<setprecision(20); rep(i,2)rep(j,2)rep(k,2){ int a=1,b=2; if(i)a=-a; if(j)b=-b; if(k)swap(a,b); dxy.eb(a,b); } /*for(int n=4;n<=100;n+=2){ cerr<<n<<endl; auto ans=sub(n); check(n,ans); } cerr<<baka<<endl;*/ int n;cin>>n; seed=baka[(n-4)/2]; auto ans=sub(n); for(auto [i,j,k]:ans){ cout<<i+1<<" "<<j+1<<" "<<k<<"\n"; } }