#ifndef NO_HEAD_FILE
#ifndef PDQSORT_H//一个排序
#define PDQSORT_H
#include<bits/stdc++.h>
#if __cplusplus>=201103L
#include<cstdint>
#include<type_traits>
#define PDQSORT_PREFER_MOVE(x) std::move(x)
#else
#define PDQSORT_PREFER_MOVE(x) (x)
#endif
using namespace std;
namespace pdqsort_detail{
enum{
insertion_sort_threshold=24,
ninther_threshold=128,
partial_insertion_sort_limit=8,
block_size=64,
cacheline_size=64
};
#if __cplusplus>=201103L
template<class T>struct is_default_compare:std::false_type{};
template<class T>struct is_default_compare<std::less<T>>:std::true_type{};
template<class T>struct is_default_compare<std::greater<T>>:std::true_type{};
#endif
template<class T>
inline int log2(T n){
int log=0;
while(n>>=1)++log;
return log;
}
template<class Iter,class Compare>
inline void insertion_sort(Iter begin,Iter end,Compare comp){
typedef typename std::iterator_traits<Iter>::value_type T;
if(begin==end)return;
for(Iter cur=begin+1;cur!=end;++cur){
Iter sift=cur,sift_1=cur-1;
if(comp(*sift,*sift_1)){
T tmp=PDQSORT_PREFER_MOVE(*sift);
do{*sift--=PDQSORT_PREFER_MOVE(*sift_1);}
while(sift!=begin&&comp(tmp,*--sift_1));
*sift=PDQSORT_PREFER_MOVE(tmp);
}
}
}
template<class Iter,class Compare>
inline void unguarded_insertion_sort(Iter begin,Iter end,Compare comp){
typedef typename std::iterator_traits<Iter>::value_type T;
if(begin==end)return;
for(Iter cur=begin+1;cur!=end;++cur){
Iter sift=cur,sift_1=cur-1;
if(comp(*sift,*sift_1)){
T tmp=PDQSORT_PREFER_MOVE(*sift);
do{*sift--=PDQSORT_PREFER_MOVE(*sift_1);}
while(comp(tmp,*--sift_1));
*sift=PDQSORT_PREFER_MOVE(tmp);
}
}
}
template<class Iter,class Compare>
inline bool partial_insertion_sort(Iter begin,Iter end,Compare comp){
typedef typename std::iterator_traits<Iter>::value_type T;
if(begin==end)return 1;
std::size_t limit=0;
for(Iter cur=begin+1;cur!=end;++cur){
Iter sift=cur,sift_1=cur-1;
if(comp(*sift,*sift_1)){
T tmp=PDQSORT_PREFER_MOVE(*sift);
do{*sift--=PDQSORT_PREFER_MOVE(*sift_1);}
while(sift!=begin&&comp(tmp,*--sift_1));
*sift=PDQSORT_PREFER_MOVE(tmp);
limit+=cur-sift;
}
if(limit>partial_insertion_sort_limit)return 0;
}
return 1;
}
template<class Iter,class Compare>
inline void sort2(Iter a,Iter b,Compare comp){
if(comp(*b,*a))std::iter_swap(a,b);
}
template<class Iter,class Compare>
inline void sort3(Iter a,Iter b,Iter c,Compare comp){
sort2(a,b,comp);sort2(b,c,comp);sort2(a,b,comp);
}
template<class T>inline T*align_cacheline(T*p){
#if defined(UINTPTR_MAX)&&__cplusplus>=201103L
std::uintptr_t ip=reinterpret_cast<std::uintptr_t>(p);
#else
std::size_t ip=reinterpret_cast<std::size_t>(p);
#endif
ip=(ip+cacheline_size-1)&-cacheline_size;
return reinterpret_cast<T*>(ip);
}
template<class Iter>inline void swap_offsets(Iter first,Iter last,
unsigned char*offsets_l,unsigned char*offsets_r,size_t num,bool use_swaps){
typedef typename std::iterator_traits<Iter>::value_type T;
if(use_swaps)for(size_t i=0;i<num;++i){
std::iter_swap(first+offsets_l[i],last-offsets_r[i]);
}else if(num>0){
Iter l=first+offsets_l[0],r=last-offsets_r[0];
T tmp(PDQSORT_PREFER_MOVE(*l));*l=PDQSORT_PREFER_MOVE(*r);
for(size_t i=1;i<num;++i){
l=first+offsets_l[i];*r=PDQSORT_PREFER_MOVE(*l);
r=last-offsets_r[i];*l=PDQSORT_PREFER_MOVE(*r);
}
*r=PDQSORT_PREFER_MOVE(tmp);
}
}
template<class Iter,class Compare>
inline std::pair<Iter,bool>
partition_right_branchless(Iter begin,Iter end,Compare comp){
typedef typename std::iterator_traits<Iter>::value_type T;
T pivot(PDQSORT_PREFER_MOVE(*begin));
Iter first=begin,last=end;
while(comp(*++first,pivot));
if(first-1==begin)while(first<last&&!comp(*--last,pivot));
else while(!comp(*--last,pivot));
bool already_partitioned=first>=last;
if(!already_partitioned){
std::iter_swap(first,last);++first;
unsigned char offsets_l_storage[block_size+cacheline_size];
unsigned char offsets_r_storage[block_size+cacheline_size];
unsigned char*offsets_l=align_cacheline(offsets_l_storage);
unsigned char*offsets_r=align_cacheline(offsets_r_storage);
Iter offsets_l_base=first,offsets_r_base=last;
size_t num_l,num_r,start_l,start_r;
num_l=num_r=start_l=start_r=0;
while(first<last){
size_t num_unknown=last-first;
size_t left_split=!num_l?(!num_r?num_unknown/2:num_unknown):0;
size_t right_split=!num_r?num_unknown-left_split:0;
if(left_split>=block_size){
for(size_t i=0;i<block_size;){
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
}
}else for(size_t i=0;i<left_split;){
offsets_l[num_l]=i++;num_l+=!comp(*first,pivot);++first;
}
if(right_split>=block_size){
for(size_t i=0;i<block_size;){
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
}
}else for(size_t i=0;i<right_split;){
offsets_r[num_r]=++i;num_r+=comp(*--last,pivot);
}
size_t num=std::min(num_l,num_r);
swap_offsets(offsets_l_base,offsets_r_base,offsets_l+start_l,
offsets_r+start_r,num,num_l==num_r);
num_l-=num,num_r-=num;
start_l+=num,start_r+=num;
if(!num_l){
start_l=0;
offsets_l_base=first;
}
if(!num_r){
start_r=0;
offsets_r_base=last;
}
}
if(num_l){
offsets_l+=start_l;
while(num_l--)std::iter_swap
(offsets_l_base+offsets_l[num_l],--last);
first=last;
}
if(num_r){
offsets_r+=start_r;
while(num_r--)std::iter_swap
(offsets_r_base-offsets_r[num_r],first),++first;
last=first;
}
}
Iter pivot_pos=first-1;
*begin=PDQSORT_PREFER_MOVE(*pivot_pos);
*pivot_pos=PDQSORT_PREFER_MOVE(pivot);
return std::make_pair(pivot_pos, already_partitioned);
}
template<class Iter,class Compare>
inline std::pair<Iter,bool>partition_right(
Iter begin,Iter end,Compare comp){
typedef typename std::iterator_traits<Iter>::value_type T;
T pivot(PDQSORT_PREFER_MOVE(*begin));
Iter first=begin,last=end;
while(comp(*++first,pivot));
if(first-1==begin)while(first<last&&!comp(*--last,pivot));
else while(!comp(*--last,pivot));
bool already_partitioned=first>=last;
while(first<last){
std::iter_swap(first,last);
while(comp(*++first,pivot));
while(!comp(*--last,pivot));
}
Iter pivot_pos=first-1;
*begin=PDQSORT_PREFER_MOVE(*pivot_pos);
*pivot_pos=PDQSORT_PREFER_MOVE(pivot);
return std::make_pair(pivot_pos,already_partitioned);
}
template<class Iter,class Compare>
inline Iter partition_left(Iter begin,Iter end,Compare comp){
typedef typename std::iterator_traits<Iter>::value_type T;
T pivot(PDQSORT_PREFER_MOVE(*begin));
Iter first=begin,last=end;
while(comp(pivot,*--last));
if(last+1==end)while(first<last&&!comp(pivot,*++first));
else while(!comp(pivot,*++first));
while(first<last){
std::iter_swap(first,last);
while(comp(pivot,*--last));
while(!comp(pivot,*++first));
}
Iter pivot_pos=last;
*begin=PDQSORT_PREFER_MOVE(*pivot_pos);
*pivot_pos=PDQSORT_PREFER_MOVE(pivot);
return pivot_pos;
}
template<class Iter, class Compare, bool Branchless>
inline void pdqsort_loop(Iter begin,Iter end,Compare comp,int bad_allowed
,bool leftmost=1){
typedef typename std::iterator_traits<Iter>::difference_type diff_t;
while(1){
diff_t size=end-begin;
if(size<insertion_sort_threshold){
if(leftmost)insertion_sort(begin,end,comp);
else unguarded_insertion_sort(begin,end,comp);
return;
}
diff_t s2=size/2;
if(size>ninther_threshold){
sort3(begin,begin+s2,end-1,comp);
sort3(begin+1,begin+(s2-1),end-2,comp);
sort3(begin+2,begin+(s2+1),end-3,comp);
sort3(begin+(s2-1),begin+s2,begin+(s2+1),comp);
std::iter_swap(begin,begin+s2);
}else sort3(begin+s2,begin,end-1,comp);
if(!leftmost&&!comp(*(begin-1),*begin)){
begin=partition_left(begin,end,comp)+1;
continue;
}
std::pair<Iter,bool>part_result=Branchless?
partition_right_branchless(begin,end,comp)
:partition_right(begin,end,comp);
Iter pivot_pos=part_result.first;
bool already_partitioned=part_result.second;
diff_t l_size,r_size=end-(pivot_pos+1);
bool highly_unbalanced=l_size<size/8||r_size<size/8;
if(highly_unbalanced){
if(--bad_allowed==0){
std::make_heap(begin,end,comp);
std::sort_heap(begin,end,comp);
return;
}
if(l_size>=insertion_sort_threshold){
std::iter_swap(begin,begin+l_size/4);
std::iter_swap(pivot_pos-1,pivot_pos-l_size/4);
if(l_size > ninther_threshold){
std::iter_swap(begin+1,begin+(l_size/4+1));
std::iter_swap(begin+2,begin+(l_size/4+2));
std::iter_swap(pivot_pos-2,pivot_pos-(l_size/4+1));
std::iter_swap(pivot_pos-3,pivot_pos-(l_size/4+2));
}
}
if(r_size>=insertion_sort_threshold){
std::iter_swap(pivot_pos+1,pivot_pos+(1+r_size/4));
std::iter_swap(end-1,end-r_size/4);
if(r_size>ninther_threshold){
std::iter_swap(pivot_pos+2,pivot_pos+(2+r_size/4));
std::iter_swap(pivot_pos+3,pivot_pos+(3+r_size/4));
std::iter_swap(end-2,end-(1+r_size/4));
std::iter_swap(end-3,end-(2+r_size/4));
}
}
}else{
if(already_partitioned&&partial_insertion_sort(begin,pivot_pos
,comp)&&partial_insertion_sort(pivot_pos+1,end,comp))return;
}
pdqsort_loop<Iter,Compare,Branchless>(begin,pivot_pos,comp,bad_allowed,leftmost);
begin=pivot_pos+1,leftmost=0;
}
}
}
template<class Iter,class Compare>
inline void pdqsort(Iter begin,Iter end,Compare comp){
if(begin==end)return;
#if __cplusplus>=201103L
pdqsort_detail::pdqsort_loop<Iter,Compare,
pdqsort_detail::is_default_compare<typename std::decay<Compare>::type>::value&&
std::is_arithmetic<typename std::iterator_traits<Iter>::value_type>
::value>(begin,end,comp,pdqsort_detail::log2(end-begin));
#else
pdqsort_detail::pdqsort_loop<Iter,Compare,0>(
begin,end,comp,pdqsort_detail::log2(end-begin));
#endif
}
template<class Iter>
inline void pdqsort(Iter begin,Iter end){
typedef typename std::iterator_traits<Iter>::value_type T;
pdqsort(begin,end,std::less<T>());
}
template<class Iter,class Compare>
inline void pdqsort_branchless(Iter begin,Iter end,Compare comp){
if(begin==end)return;
pdqsort_detail::pdqsort_loop<Iter,Compare,1>(
begin,end,comp,pdqsort_detail::log2(end-begin));
}
template<class Iter>
inline void pdqsort_branchless(Iter begin,Iter end){
typedef typename std::iterator_traits<Iter>::value_type T;
pdqsort_branchless(begin,end,std::less<T>());
}
#undef PDQSORT_PREFER_MOVE
#endif
using namespace std;
#endif //Maybe it don't need head files.
#pragma GCC Optimize 1
#pragma GCC Optimize 2
#pragma GCC Optimize 3
#ifndef TRAIN_HEAD //It's so long!
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#pragma GCC optimize(1)
#pragma GCC optimize("Og")
#pragma GCC optimize("Os")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#endif
#define inl __inline__ __attribute__((always_inline))
namespace fastIO{
#ifdef __cplusplus
extern "C"{
#endif
#define get getchar
#define put putchar
#define ioFast1 ios::sync_with_stdio(0)
#define ioFast2 cin.tie(0),cout.tie(0)//Only cin,cout
#define ioFast ioFast1,ioFast2
inl int read(){//It can be faster ^_^
register int f=0,a=0,c;
for(;!isdigit(c=get());c^45||++f);
for(a=c&15;isdigit(c=get());a=a*10+(c&15));
f&&(a=-a);return a;
}
inl void write(int x){
register short n=0,ch[10];
if(!x){putchar(48);return;}
if(x<0)putchar(45),x=-x;
for(;x;ch[n++]=x%10,x/=10);
while(n--)putchar(ch[n]+48);
}
#ifdef __cplusplus
}
#endif
}
namespace Small_Func{
#define sswap(a,b) {typeof(a)t=a;a=b;b=t;}
auto mmax=[](int a,int b){return a>b?a:b;};//C++11
auto mmin=[](int a,int b){return a<b?a:b;};
//#define mmax(a,b) ((a)>(b)?(a):(b))
//#define mmin(a,b) ((a)<(b)?(a):(b))
#define Sqrt __builtin_sqrt
inl int isPrime(int x){
if(x<2)return 0;
for(int i=2;i<=Sqrt(x);i++){
if(x%i==0)return 0;
}
return 1;
}
inl int _abs(int x){return x>0?x:-x;}
int sum(int x,...){
int s=0;va_list p;va_start(p,x);
for(int i=0;i<x;i++)s+=va_arg(p,int);
return s;
}
#ifdef __cplusplus
template<int p,int i>struct is_prime{//整活内容
enum{prim=p%i&&is_prime<(i>2?p:0),i-1>::prim};
};
template<>struct is_prime<0,0>{enum{prim=1};};
template<>struct is_prime<0,1>{enum{prim=1};};
template<int i>struct prime_print{
prime_print<i-1>pp;
void print(){pp.print();if(is_prime<i,i-1>::prim)cout<<" "<<i;}
};
template<>struct prime_print<2>{
void print(){cout<<2;}
};
#define Isprime(a) ((a)==2?1:is_prime<(a),(a)-1>::prim)
#endif
}
namespace Geometry{//Studying
using::fabs;
using db=double;//or"typedef double db;"
//or"#define db double;"
const db pi=acos(-1),eps=1e-8;
inl int sgn(db x){
if(fabs(x)<eps)return 0;
return x<0?-1:1;
}
inl int dcmp(db a,db b){
if(fabs(a-b)<eps)return 0;
return a<b?-1:1;
}
struct Point{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
};
inl double Distance(Point a,Point b){return hypot(a.x-b.x,a.y-b.y);}
typedef Point Vector;
inl Point operator+(Point a,Point b){return Point(a.x+b.x,a.y+b.y);}
inl Point operator-(Point a,Point b){return Point(a.x-b.x,a.y-b.y);}
inl Point operator*(Point a,db k){return Point(a.x*k,a.y*k);}
inl Point operator/(Point a,db k){return Point(a.x/k,a.y/k);}
inl bool operator==(Point a,Point b){return sgn(a.x-b.x)==0&&sgn(a.y-b.y)==0;}
inl bool operator!=(Point a,Point b){return !(a==b);}
inl db Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
inl db Len2(Vector a){return Dot(a,a);}
inl db Len(Vector a){return sqrt(Len2(a));}
inl db Angle(Vector a,Vector b){return acos(Dot(a,b)/Len(a)/Len(b));}
inl db Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
inl db Area2(Point a,Point b,Point c){return Cross(b-a,c-a);}
inl Vector Rotate(Vector a,double rad){
return Vector(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
inl Vector Normal(Vector a){return Vector(-a.y/Len(a),a.x/Len(a));}
inl bool Parallel(Vector a,Vector b){return sgn(Cross(a,b))==0;}
struct Line{
Point p1,p2;
Line(){}
Line(Point p1,Point p2):p1(p1),p2(p2){}
Line(Point p,double angle){
p1=p;
if(sgn(angle-pi/2)==0)p2=p1+Point(0,1);
else p2=p1+Point(1,tan(angle));
}
Line(double a,double b,double c){//ax+by+c=0
if(sgn(a)==0){
p1=Point(0,-c/b);
p2=Point(1,-c/b);
}
else if(sgn(b)==0){
p1=Point(-c/a,0);
p2=Point(-c/a,1);
}
else{
p1=Point(0,-c/b);
p2=Point(1,(-c-a)/b);
}
}
};
using Segment=Line;
int Point_line_relation(Point p,Line v){
int c=sgn(Cross(p-v.p1,v.p2-v.p1));
if(c<0)return 1;//left
if(c>0)return 2;//right
return 0;//on the line
}
bool Point_on_seg(Point p,Line v){//0:p isn't on v ; 1:p is on v
return sgn(Cross(p-v.p1,v.p2-v.p1))==0&&sgn(Dot(p-v.p1,p-v.p2))<=0;
}
double Dis_point_line(Point p,Line v){
return fabs(Cross(p-v.p1,v.p2-v.p1))/Distance(v.p1,v.p2);
}
Point Point_line_proj(Point p,Line v){
double k=Dot(v.p2-v.p1,p-v.p1)/Len2(v.p2-v.p1);
return v.p1+(v.p2-v.p1)*k;
}
Point Point_line_symmetry(Point p,Line v){
Point q=Point_line_proj(p,v);
return Point(2*q.x-p.x,2*q.y-p.y);
}
double Dis_point_seg(Point p,Segment v){
if(sgn(Dot(p-v.p1,v.p2-v.p1))<0||sgn(Dot(p-v.p2,v.p1-v.p2))<0)
return min(Distance(p,v.p1),Distance(p,v.p2));
return Dis_point_line(p,v);
}
int Line_relation(Line v1,Line v2){
if(sgn(Cross(v1.p2-v1.p1,v2.p2-v2.p1))==0){
if(Point_line_relation(v1.p1,v2)==0)return 1;//1:重合
return 0; //0:平行
}
return 2; //2:相交
}
Point Cross_point(Point a,Point b,Point c,Point d){
double s1=Cross(b-a,c-a),s2=Cross(b-a,d-a);
return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);
}
bool Cross_segment(Point a,Point b,Point c,Point d){
double c1=Cross(b-a,c-a),c2=Cross(b-a,d-a);
double d1=Cross(d-c,a-c),d2=Cross(d-c,b-c);
return sgn(c1)*sgn(c2)<0&&sgn(d1)*sgn(d2)<0;//1:相交 0:不相交
}
int Point_in_polygon(Point pt,Point*p,int n){
for(int i=0;i<n;i++)if(p[i]==pt)return 3;//3:点在多边形顶点上
for(int i=1;i<n;i++){
Line v=Line(p[i],p[(i+1)%n]);
if(Point_on_seg(pt,v))return 2;//3:点在多边形边上
}
int num=0;
for(int i=0;i<n;i++){
int j=(i+1)%n;
int c=sgn(Cross(pt-p[j],p[i]-p[j]));
int u=sgn(p[i].y-pt.y),v=sgn(p[j].y-pt.y);
if(c>0&&u<0&&v>=0)num++;
if(c<0&&u>=0&&v<0)num--;
}
return num!=0; //1:点在内部 0:点在外部
}
double Polygon_area(Point*p,int n){
double area=0;
for(int i=0;i<n;i++)
area+=Cross(p[i],p[(i+1)%n]);
return area/2;
}
int Convex_hull(Point*p,int n,Point*ch){
n=unique(p,p+n)-p;
sort(p,p+n,[](Point a,Point b){
return sgn(a.x-b.x)<0||sgn(a.x-b.x)==0&&sgn(a.y-b.y)<0;
});
int v=0;
for(int i=0;i<n;i++){
while(v>1&&sgn(Cross(ch[v-1]-ch[v-2],p[i]-ch[v-1]))<=0)v--;
ch[v++]=p[i];
}
int j=v;
for(int i=n-2;i>=0;i--){
while(v>j&&sgn(Cross(ch[v-1]-ch[v-2],p[i]-ch[v-1]))<=0)v--;
ch[v++]=p[i];
}
if(n>1)v--;return v;
}
//...
}
namespace Template{//Studying
//...
}
namespace MTL{//My Template Library
using namespace Template;
template<class T>class Array{
// private:
int n;
T*num;
public:
static const int maxn=1e5;
Array(){num=new T[maxn];}
Array(int n):n(n){num=new T[n];}
int getlen(){return n;}
T*begin(){return num;}
T*end(){return num+n;}
void setlen(int _){n=_;delete[]num;num=new T[n];}
T&operator[](int i){return num[i];}
~Array(){delete[]num;}
bool operator==(Array a){
if(a.n!=this->n)return 0;
for(int i=0;i<this->n;i++){
if(this->num[i]!=a.num[i])return 0;
}
return 1;
}
bool operator!=(Array a){
if(a.n!=this->n)return 1;
for(int i=0;i<this->n;i++){
if(this->num[i]!=a.num[i])return 1;
}
return 0;
}
template<typename Cmp>
void sort(Cmp cmp){
sort(this->begin(),this->end(),cmp);
}
T*find(T x){
for(T*i=num;i<num+n;i++){
if(*i==x)return i;
}
return this->end();
}
Array operator+(Array a){
Array b(n+a.n);
for(int i=0;i<n;i++)b[i]=num[i];
for(int i=0;i<a.n;i++)b[i+n]=a.num[i];
return b;
}
//...
};
template<class T>
Array<T>operator+=(Array<T>&a,Array<T>b){
a=a+b;return a;
}
}
//...
namespace Lit{
#define pt st.top();st.pop()
map<string,int>mp,lab;
struct arr{
string name;
int len,a[1005];
}ar[1005],ppq;
int mad;
int num(string u){
stack<int>st;string t;
for(int i=0;i<u.size();i++){
if(u[i]!=' ')t+=u[i];
if(u[i]==' '||i==u.size()-1){
if(t=="+"){int x=pt;int y=pt;st.push(x+y);}
else if(t=="-"){int x=pt;int y=pt;st.push(y-x);}
else if(t=="*"){int x=pt;int y=pt;st.push(x*y);}
else if(t=="/"){int x=pt;int y=pt;st.push(y/x);}
else if(t=="%"){int x=pt;int y=pt;st.push(y%x);}
else if(t=="&"){int x=pt;int y=pt;st.push(y&x);}
else if(t=="|"){int x=pt;int y=pt;st.push(y|x);}
else if(t=="^"){int x=pt;int y=pt;st.push(y^x);}
else if(t=="!"){int x=pt;st.push(!x);}
else if(t=="~"){int x=pt;st.push(~x);}
else if(t==">"){int x=pt;int y=pt;st.push(y>x);}
else if(t=="<"){int x=pt;int y=pt;st.push(y<x);}
else if(t==">="){int x=pt;int y=pt;st.push(y>=x);}
else if(t=="<="){int x=pt;int y=pt;st.push(y<=x);}
else if(t=="=="){int x=pt;int y=pt;st.push(y==x);}
else if(t=="!="){int x=pt;int y=pt;st.push(y!=x);}
else if(t=="&&"){int x=pt;int y=pt;st.push(y&&x);}
else if(t=="||"){int x=pt;int y=pt;st.push(y||x);}
else if(t[0]>='0'&&t[0]<='9')st.push(atoi(t.c_str()));
else if(t.find('[')!=string::npos){
int pos=t.find('['),jj;
string q=t.substr(0,pos);
jj=atoi(t.substr(pos+1).c_str());
for(int i=1;i<=mad;i++){
if(ar[i].name==q){
st.push(ar[i].a[jj]);
break;
}
}
}
else st.push(mp[t]);
t="";
}
}
return st.top();
}
int cnt,nu[10005],pos,p;
string s[1005];
void run(int x){
for(int i=x;i<=cnt;i++){
if(s[i].substr(0,3)=="def"){
string t="";
for(int j=4;j<s[i].size();j++){
if(s[i][j]!=' ')t+=s[i][j];
if(s[i][j]==' '||j==s[i].size()-1)mp[t]=0,t="";
}
}
else if(s[i].substr(0,3)=="daf"){
string t="";int j=4;
for(;s[i][j]!=' ';j++)t+=s[i][j];
int lp=num(s[i].substr(j+1));
ppq.name=t,ppq.len=lp;ar[++mad]=ppq;
}
else if(s[i].substr(0,5)=="print"){
if(s[i][5]==' ')cout<<num(s[i].substr(6));
else if(s[i][5]=='\"')cout<<s[i].substr(6);
else cout<<(char)num(s[i].substr(6));
}
else if(s[i].substr(0,4)=="scan"){
if(s[i].find('[')==string::npos)
mp[s[i].substr(5)]=nu[++p];
else{
string t=s[i].substr(5);
int pos=t.find('['),jj;
string q=t.substr(0,pos);
jj=atoi(t.substr(pos+1).c_str());
for(int k=1;k<=mad;k++){
if(ar[k].name==q){
ar[k].a[jj]=nu[++p];
break;
}
}
}
}
else if(s[i].substr(0,2)=="eq"){
string t="";int j=3;
for(;s[i][j]!=' ';j++)t+=s[i][j];
if(t.find('[')!=string::npos){
int pos=t.find('['),jj;
string q=t.substr(0,pos);
jj=atoi(t.substr(pos+1).c_str());
for(int k=1;k<=mad;k++){
if(ar[k].name==q){
ar[k].a[jj]=num(s[i].substr(j+1));
break;
}
}
}
else mp[t]=num(s[i].substr(j+1));
}
else if(s[i].substr(0,4)=="goto"){
run(lab[s[i].substr(5)]+1);
return;
}
else if(s[i].substr(0,2)=="if"){
string t=s[i].substr(3);
int ppp=num(t),j=i+1;
for(;s[j]!="endf";j++);
if(ppp)run(i+1);
else run(j+1);
return;
}
}
}
void _main(){
puts("--------<Lit Programming Language>--------");
puts("Thank you for using this Programming Language!");
puts("It\'s a little Programming Language, It\'s name is Lit.");
puts("--------------<CODE>-------------");
for(int i=1;;i++){
printf("%3d. | ",i);
getline(cin,s[++cnt]);
if(s[cnt]=="end"){
cnt--;
break;
}
}
puts("--------------<INPUT>-------------");
for(int i=1;i<=cnt;i++){
if(s[i].substr(0,3)=="lab")lab[s[i].substr(4)]=i;
if(s[i].substr(0,4)=="scan")cin>>nu[++pos];
}
puts("--------------<OUTPUT>--------------");
run(1);
puts("\n--------------<END>--------------");
}
}
namespace Algorithm{
using namespace Small_Func;
using namespace Geometry;
using namespace Lit;
//...
}
namespace MyStd{
using namespace MTL;
using namespace fastIO;
using namespace Algorithm;
template<typename...>struct TypeList;
template<typename Head,typename...Tails>
struct TypeList<Head,Tails...>{
using head=Head;
using tails=TypeList<Tails...>;
};
template<>struct TypeList<>{};
template<typename TList>struct Length;
template<>
struct Length<TypeList<>>{
static constexpr int value=0;
};
template<typename Head,typename...Types>
struct Length<TypeList<Head,Types...>>{
static constexpr int value=Length<TypeList<Types...>>::value+1;
};
template<typename TList,unsigned int index>struct TypeAt;
template<typename Head,typename...Args>
struct TypeAt<TypeList<Head,Args...>,0>{
using type=Head;
};
template<typename Head,typename...Args,unsigned int i>
struct TypeAt<TypeList<Head,Args...>,i>{
static_assert(i<sizeof...(Args)+1,"i out of range");
using type=typename TypeAt<TypeList<Args...>,i-1>::type;
};
template<typename TList,typename T>struct IndexOf;
template<typename Head,typename...Tails,typename T>
struct IndexOf<TypeList<Head,Tails...>,T>{
private:
using Result=IndexOf<TypeList<Tails...>,T>;
public:
static constexpr int value=is_same<Head,T>::value?0:
(Result::value==-1?-1:Result::value+1);
};
template<typename T>
struct IndexOf<TypeList<>,T>{
static constexpr int value=-1;
};
template<typename,typename>struct Append;
template<typename...TList,typename T>
struct Append<TypeList<TList...>,T>{
using type=TypeList<TList...,T>;
};
template<typename T,typename...TList>
struct Append<T,TypeList<TList...>>{
using type=TypeList<T,TList...>;
};
template<typename...TListLeft,typename...TListRight>
struct Append<TypeList<TListLeft...>,TypeList<TListRight...>>{
using type=TypeList<TListLeft...,TListRight...>;
};
template<typename TList,typename T>struct Erase;
template<typename Head,typename...Tails,typename T>
struct Erase<TypeList<Head,Tails...>,T>{
using type=typename Append<Head,typename Erase<TypeList<Tails...>,T>::type>::type;
};
template<typename...Tails,typename T>
struct Erase<TypeList<T,Tails...>,T>{
using type=TypeList<Tails...>;
};
template<typename T>
struct Erase<TypeList<>,T>{
using type=TypeList<>;
};
template<typename TList,typename T>struct EraseAll;
template<typename Head,typename...Tails,typename T>
struct EraseAll<TypeList<Head,Tails...>,T>{
using type=typename Append<Head,typename EraseAll<TypeList<Tails...>,T>::type>::type;
};
template<typename...Tails,typename T>
struct EraseAll<TypeList<T,Tails...>,T>{
using type=typename EraseAll<TypeList<Tails...>,T>::type;
};
template<typename T>
struct EraseAll<TypeList<>,T>{
using type=TypeList<>;
};
template<typename TList>struct NoDuplicates;
template<>
struct NoDuplicates<TypeList<>>{
using type=TypeList<>;
};
template<typename Head,typename...Tails>
struct NoDuplicates<TypeList<Head, Tails...>>{
private:
using L1=typename NoDuplicates<TypeList<Tails...>>::type;
using L2=typename Erase<L1,Head>::type;
public:
using type=typename Append<Head,L2>::type;
};
template<typename TList,typename Old,typename New>struct Replace;
template<typename T,typename U>
struct Replace<TypeList<>,T,U>{
using type=TypeList<>;
};
template<typename...Tails,typename T,typename U>
struct Replace<TypeList<T,Tails...>,T,U>{
using type=typename Append<U,TypeList<Tails...>>::type;
};
template<typename Head,typename...Tails,typename T,typename U>
struct Replace<TypeList<Head,Tails...>,T,U>{
using type=typename Append<Head,typename Replace<TypeList<Tails...>,T,U>::type>::type;
};
//The end of TypeList
template<class T,class...U>
class Tuple{
T a;Tuple<U...>b;
public:
template<class P>
P&get(){
if(is_same<P,T>::value)return(P&)a;
return b.get<P>();
}
template<int i>
typename TypeAt<TypeList<T,U...>,i>::type&get(){
if(i)return(typename TypeAt<TypeList<T,U...>,i>::type&)b.get<i-1>();
return a;
}
};
template<class T>
class Tuple<T>{
T a;
public:
template<class P>P&get(){return(P&)a;}
template<int i>T&get(){return a;}
};
//The end of Tuple
}
#ifndef DEF_STD
using namespace MyStd;
#endif
signed __cdecl main(
int argc,
const char**argv,
const char**envp){
//some code:
#ifndef LITLANG
_main();
#endif
return system("pause");
}
本文来自博客园,作者:夏一锐,转载请注明原文链接:https://www.cnblogs.com/2021changqing52/p/sui-bi.html
(不过似乎不会有人转载)