循环队列
template<typename item,const int _size>
class cirqueue{
private:
item q[_size];
int head,tail;
int len;
public:
cirqueue(){
memset(q,0,sizeof(q));
head=tail=len=0;
}
void push(item const &x){
q[tail]=x;
len++;
tail=(tail+1)%_size;
}
void pop(){
head=(head+1)%_size;
len--;
}
item front()const{
return q[head];
}
int size()const{
return len;
}
bool empty()const{
return len==0;
}
item back()const{
return q[tail];
}
};
优先级队列
template<typename item,const int _size,bool (*check)(const item&,const item&)>
class prioqueue{
#define ss(x,y) check(q[x],q[y])
private:
item q[_size+1];
int len;
void swp(const int &x,const int &y){
item k=q[x];
q[x]=q[y];
q[y]=k;
}
public:
prioqueue(){
memset(q,0,sizeof(q));
len=0;
}
void push(const item &x){
q[++len]=x;
int now=len;
while(now>1&&!ss(now>>1,now)){
swp(now,now>>1);
now>>=1;
}
}
void pop(){
q[1]=q[len--];
int now=1;
while((now<<1)<=len){
if((now<<1|1)<=len){
if(ss(now,now<<1)&&ss(now,now<<1|1))break;
if(ss(now<<1,now<<1|1))swp(now,now<<1),now<<=1;
else swp(now,now<<1|1),now=now<<1|1;
}
else{
if(ss(now<<1,now))
swp(now,now<<1);
break;
}
}
}
item top()const{
return q[1];
}
bool empty()const{
return len==0;
}
int size()const{
return len;
}
#undef ss
};
树状数组
template<typename item,const int _size>
class sum_treearray{
private:
item c[_size+1];
public:
sum_treearray(){
memset(c,0,sizeof(c));
}
void update(int i,item x){
for(;i<=_size;i+=i&-i)c[i]+=x;
}
item query(int i){
item sum=0;
for(;i>0;i-=i&-i)sum+=c[i];
return sum;
}
item query(int i,int j){
return query(j)-query(i-1);
}
};
template<typename item,const int _size,item (*add)(const item&,const item&)>
class treearray{
private:
item c[_size+1];
public:
treearray(){
memset(c,0,sizeof(c));
}
void update(int i,item x){
item last;
c[i]+=x;
last=c[i];
for(i=i+(i&-i);i<=_size;i+=(i&-i))c[i]=add(c[i],last),last=c[i];
}
item query(int i){
item sum=c[i];
for(i=i-(i&-i);i>0;i-=(i&-i))sum=add(sum,c[i]);
return sum;
}
};
线段树
template<typename item,const int _size>
class sum_linetree{
private:
item tree[_size<<2],f[_size<<2];
void up(int rt){
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void down(int l,int r,int rt){
if(f[rt]>0){
tree[rt<<1]+=f[rt]*l;
tree[rt<<1|1]+=f[rt]*r;
f[rt<<1]+=f[rt];
f[rt<<1|1]+=f[rt];
f[rt]=0;
}
}
void buildadd(item *a,int l,int r,int rt){
if(l==r){
tree[rt]=a[l];
return;
}
int m=(l+r)>>1;
buildadd(a,l,m,rt<<1);
buildadd(a,m+1,r,rt<<1|1);
up(rt);
}
void updateadd(int head,int tail,item x,int l,int r,int rt){
if(head<=l&&r<=tail){
tree[rt]+=x;
f[rt]+=x;
return;
}
int m=(l+r)>>1;
down(m-l+1,r-m,rt);
if(head<=m)updateadd(head,tail,x,l,m,rt<<1);
if(m+1<=tail)updateadd(head,tail,x,m+1,r,rt<<1|1);
up(rt);
}
item queryadd(int head,int tail,int l,int r,int rt){
if(head<=l&&r<=tail){
return tree[rt];
}
int m=(l+r)>>1;
down(m-l+1,r-m,rt);
item sum=0;
if(head<=m)sum+=queryadd(head,tail,l,m,rt<<1);
if(m+1<=tail)sum+=queryadd(head,tail,m+1,r,rt<<1|1);
return sum;
}
public:
sum_linetree(){
memset(tree,0,sizeof(tree));
memset(f,0,sizeof(f));
}
void build(item *a){
buildadd(a,1,_size,1);
}
void update(int head,int tail,item x){
updateadd(head,tail,x,1,_size,1);
}
item query(int head,int tail){
return queryadd(head,tail,1,_size,1);
}
};
template<typename item,const int _size,item (*add)(const item&,const item&)>
class linetree{
private:
item tree[_size<<2],f[_size<<2];
void up(int rt){
tree[rt]=add(tree[rt<<1],tree[rt<<1|1]);
}
void down(int rt){
if(f[rt]>0){
tree[rt<<1]+=f[rt];
tree[rt<<1|1]+=f[rt];
f[rt<<1]+=f[rt];
f[rt<<1|1]+=f[rt];
f[rt]=0;
}
}
void buildadd(item *a,int l,int r,int rt){
if(l==r){
tree[rt]=a[l];
return;
}
int m=(l+r)>>1;
buildadd(a,l,m,rt<<1);
buildadd(a,m+1,r,rt<<1|1);
up(rt);
}
void updateadd(int head,int tail,item x,int l,int r,int rt){
if(head<=l&&r<=tail){
tree[rt]+=x;
f[rt]+=x;
return;
}
int m=(l+r)>>1;
down(rt);
if(head<=m)updateadd(head,tail,x,l,m,rt<<1);
if(m+1<=tail)updateadd(head,tail,x,m+1,r,rt<<1|1);
up(rt);
}
item queryadd(int head,int tail,int l,int r,int rt){
if(head<=l&&r<=tail){
return tree[rt];
}
int m=(l+r)>>1;
down(rt);
if(head<=m&&m+1<=tail)return add(queryadd(head,tail,l,m,rt<<1),queryadd(head,tail,m+1,r,rt<<1|1));
if(head<=m)return queryadd(head,tail,l,m,rt<<1);
return queryadd(head,tail,m+1,r,rt<<1|1);
}
public:
linetree(){
memset(tree,0,sizeof(tree));
memset(f,0,sizeof(f));
}
void build(item *a){
buildadd(a,1,_size,1);
}
void update(int head,int tail,item x){
updateadd(head,tail,x,1,_size,1);
}
item query(int head,int tail){
return queryadd(head,tail,1,_size,1);
}
};
哈希
template<typename item,int _size>
class open_hash{
private:
item f[_size];
int g[_size];
int change(int x){
return x%_size;
}
int change(long long x){
return x%_size;
}
int change(char x[]){
int kk=0;
for(int i=0;i<strlen(x);i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(string x){
int kk=0;
for(int i=0;i<x.length();i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(double x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
int change(float x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
public:
open_hash(){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
}
void add(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
f[pos]=x;
g[pos]++;
}
int get(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
return g[pos];
}
};
template<typename item,int _size,int (*change)(item)>
class self_open_hash{
private:
item f[_size];
int g[_size];
public:
self_open_hash(){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
}
void add(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
f[pos]=x;
g[pos]++;
}
int get(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
return g[pos];
}
};
template<typename item,int _size>
class list_hash{
private:
item a[_size];
int nex[_size],head[_size],k,g[_size];
int change(int x){
return x%_size;
}
int change(long long x){
return x%_size;
}
int change(char x[]){
int kk=0;
for(int i=0;i<strlen(x);i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(string x){
int kk=0;
for(int i=0;i<x.length();i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(double x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
int change(float x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
public:
list_hash(){
memset(a,0,sizeof(a));
memset(nex,0,sizeof(nex));
memset(head,-1,sizeof(head));
memset(g,0,sizeof(g));
k=0;
}
void add(const item &x){
int pos=change(x),now=head[pos];
while(now!=-1){
if(a[now]==x)break;
now=nex[now];
}
if(now==-1){
a[k]=x;
g[k]=1;
nex[k]=head[pos];
head[pos]=k++;
}
else g[now]++;
}
int get(const item &x){
int pos=change(x),now=head[pos];
while(now!=-1){
if(a[now]==x)break;
now=nex[now];
}
if(now==-1)return -1;
return g[now];
}
};
template<typename item,int _size,int (*change)(item)>
class self_list_hash{
private:
item a[_size];
int nex[_size],head[_size],k,g[_size];
public:
self_list_hash(){
memset(a,0,sizeof(a));
memset(nex,0,sizeof(nex));
memset(head,-1,sizeof(head));
memset(g,0,sizeof(g));
k=0;
}
void add(const item &x){
int pos=change(x),now=head[pos];
while(now!=-1){
if(a[now]==x)break;
now=nex[now];
}
if(now==-1){
a[k]=x;
g[k]=1;
nex[k]=head[pos];
head[pos]=k++;
}
else g[now]++;
}
int get(const item &x){
int pos=change(x),now=head[pos];
while(now!=0){
if(a[now]==x)break;
now=nex[now];
}
if(now==0)return -1;
return g[now];
}
};
总和
template<typename item,const int _size>
class cirqueue{
private:
item q[_size];
int head,tail;
int len;
public:
cirqueue(){
memset(q,0,sizeof(q));
head=tail=len=0;
}
void push(item const &x){
q[tail]=x;
len++;
tail=(tail+1)%_size;
}
void pop(){
head=(head+1)%_size;
len--;
}
item front()const{
return q[head];
}
int size()const{
return len;
}
bool empty()const{
return len==0;
}
item back()const{
return q[tail];
}
};
template<typename item,const int _size,bool (*check)(const item&,const item&)>
class prioqueue{
#define check(x,y) check(q[x],q[y])
private:
item q[_size+1];
int len;
void swp(const int &x,const int &y){
item k=q[x];
q[x]=q[y];
q[y]=k;
}
public:
prioqueue(){
memset(q,0,sizeof(q));
len=0;
}
void push(const item &x){
q[++len]=x;
int now=len;
while(now>1&&!check(now>>1,now)){
swp(now,now>>1);
now>>=1;
}
}
void pop(){
q[1]=q[len--];
int now=1;
while((now<<1)<=len){
if((now<<1|1)<=len){
if(check(now,now<<1)&&check(now,now<<1|1))break;
if(check(now<<1,now<<1|1))swp(now,now<<1),now<<=1;
else swp(now,now<<1|1),now=now<<1|1;
}
else{
if(check(now<<1,now))
swp(now,now<<1);
break;
}
}
}
item top()const{
return q[1];
}
bool empty()const{
return len==0;
}
int size()const{
return len;
}
};
template<typename item,const int _size>
class sum_treearray{
private:
item c[_size+1];
public:
sum_treearray(){
memset(c,0,sizeof(c));
}
void update(int i,item x){
for(;i<=_size;i+=i&-i)c[i]+=x;
}
item query(int i){
item sum=0;
for(;i>0;i-=i&-i)sum+=c[i];
return sum;
}
item query(int i,int j){
return query(j)-query(i-1);
}
};
template<typename item,const int _size,item (*add)(const item&,const item&)>
class treearray{
private:
item c[_size+1];
public:
treearray(){
memset(c,0,sizeof(c));
}
void update(int i,item x){
item last;
c[i]+=x;
last=c[i];
for(i=i+(i&-i);i<=_size;i+=(i&-i))c[i]=add(c[i],last),last=c[i];
}
item query(int i){
item sum=c[i];
for(i=i-(i&-i);i>0;i-=(i&-i))sum=add(sum,c[i]);
return sum;
}
};
template<typename item,const int _size>
class sum_linetree{
private:
item tree[_size<<2],f[_size<<2];
void up(int rt){
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void down(int l,int r,int rt){
if(f[rt]>0){
tree[rt<<1]+=f[rt]*l;
tree[rt<<1|1]+=f[rt]*r;
f[rt<<1]+=f[rt];
f[rt<<1|1]+=f[rt];
f[rt]=0;
}
}
void buildadd(item *a,int l,int r,int rt){
if(l==r){
tree[rt]=a[l];
return;
}
int m=(l+r)>>1;
buildadd(a,l,m,rt<<1);
buildadd(a,m+1,r,rt<<1|1);
up(rt);
}
void updateadd(int head,int tail,item x,int l,int r,int rt){
if(head<=l&&r<=tail){
tree[rt]+=x;
f[rt]+=x;
return;
}
int m=(l+r)>>1;
down(m-l+1,r-m,rt);
if(head<=m)updateadd(head,tail,x,l,m,rt<<1);
if(m+1<=tail)updateadd(head,tail,x,m+1,r,rt<<1|1);
up(rt);
}
item queryadd(int head,int tail,int l,int r,int rt){
if(head<=l&&r<=tail){
return tree[rt];
}
int m=(l+r)>>1;
down(m-l+1,r-m,rt);
item sum=0;
if(head<=m)sum+=queryadd(head,tail,l,m,rt<<1);
if(m+1<=tail)sum+=queryadd(head,tail,m+1,r,rt<<1|1);
return sum;
}
public:
sum_linetree(){
memset(tree,0,sizeof(tree));
memset(f,0,sizeof(f));
}
void build(item *a){
buildadd(a,1,_size,1);
}
void update(int head,int tail,item x){
updateadd(head,tail,x,1,_size,1);
}
item query(int head,int tail){
return queryadd(head,tail,1,_size,1);
}
};
template<typename item,const int _size,item (*add)(const item&,const item&)>
class linetree{
private:
item tree[_size<<2],f[_size<<2];
void up(int rt){
tree[rt]=add(tree[rt<<1],tree[rt<<1|1]);
}
void down(int rt){
if(f[rt]>0){
tree[rt<<1]+=f[rt];
tree[rt<<1|1]+=f[rt];
f[rt<<1]+=f[rt];
f[rt<<1|1]+=f[rt];
f[rt]=0;
}
}
void buildadd(item *a,int l,int r,int rt){
if(l==r){
tree[rt]=a[l];
return;
}
int m=(l+r)>>1;
buildadd(a,l,m,rt<<1);
buildadd(a,m+1,r,rt<<1|1);
up(rt);
}
void updateadd(int head,int tail,item x,int l,int r,int rt){
if(head<=l&&r<=tail){
tree[rt]+=x;
f[rt]+=x;
return;
}
int m=(l+r)>>1;
down(rt);
if(head<=m)updateadd(head,tail,x,l,m,rt<<1);
if(m+1<=tail)updateadd(head,tail,x,m+1,r,rt<<1|1);
up(rt);
}
item queryadd(int head,int tail,int l,int r,int rt){
if(head<=l&&r<=tail){
return tree[rt];
}
int m=(l+r)>>1;
down(rt);
if(head<=m&&m+1<=tail)return add(queryadd(head,tail,l,m,rt<<1),queryadd(head,tail,m+1,r,rt<<1|1));
if(head<=m)return queryadd(head,tail,l,m,rt<<1);
return queryadd(head,tail,m+1,r,rt<<1|1);
}
public:
linetree(){
memset(tree,0,sizeof(tree));
memset(f,0,sizeof(f));
}
void build(item *a){
buildadd(a,1,_size,1);
}
void update(int head,int tail,item x){
updateadd(head,tail,x,1,_size,1);
}
item query(int head,int tail){
return queryadd(head,tail,1,_size,1);
}
};
template<typename item,int _size>
class open_hash{
private:
item f[_size];
int g[_size];
int change(int x){
return x%_size;
}
int change(long long x){
return x%_size;
}
int change(char x[]){
int kk=0;
for(int i=0;i<strlen(x);i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(string x){
int kk=0;
for(int i=0;i<x.length();i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(double x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
int change(float x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
public:
open_hash(){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
}
void add(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
f[pos]=x;
g[pos]++;
}
int get(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
return g[pos];
}
};
template<typename item,int _size,int (*change)(item)>
class self_open_hash{
private:
item f[_size];
int g[_size];
public:
self_open_hash(){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
}
void add(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
f[pos]=x;
g[pos]++;
}
int get(const item &x){
int pos=change(x);
while(g[pos]){
if(f[pos]==x)break;
pos=(pos+1)%_size;
}
return g[pos];
}
};
template<typename item,int _size>
class list_hash{
private:
item a[_size];
int nex[_size],head[_size],k,g[_size];
int change(int x){
return x%_size;
}
int change(long long x){
return x%_size;
}
int change(char x[]){
int kk=0;
for(int i=0;i<strlen(x);i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(string x){
int kk=0;
for(int i=0;i<x.length();i++)kk=((long long)kk*128%_size+(int)x[i])%_size;
return kk;
}
int change(double x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
int change(float x){
int kk;
if(x>_size)kk=(int)x-(int)(x/_size)*x;
else x=(long long)((long long)(x)%_size*x)%_size,kk=(int)x-(int)(x/_size)*x;
return kk;
}
public:
list_hash(){
memset(a,0,sizeof(a));
memset(nex,0,sizeof(nex));
memset(head,-1,sizeof(head));
memset(g,0,sizeof(g));
k=0;
}
void add(const item &x){
int pos=change(x),now=head[pos];
while(now!=-1){
if(a[now]==x)break;
now=nex[now];
}
if(now==-1){
a[k]=x;
g[k]=1;
nex[k]=head[pos];
head[pos]=k++;
}
else g[now]++;
}
int get(const item &x){
int pos=change(x),now=head[pos];
while(now!=-1){
if(a[now]==x)break;
now=nex[now];
}
if(now==-1)return -1;
return g[now];
}
};
template<typename item,int _size,int (*change)(item)>
class self_list_hash{
private:
item a[_size];
int nex[_size],head[_size],k,g[_size];
public:
self_list_hash(){
memset(a,0,sizeof(a));
memset(nex,0,sizeof(nex));
memset(head,-1,sizeof(head));
memset(g,0,sizeof(g));
k=0;
}
void add(const item &x){
int pos=change(x),now=head[pos];
while(now!=-1){
if(a[now]==x)break;
now=nex[now];
}
if(now==-1){
a[k]=x;
g[k]=1;
nex[k]=head[pos];
head[pos]=k++;
}
else g[now]++;
}
int get(const item &x){
int pos=change(x),now=head[pos];
while(now!=0){
if(a[now]==x)break;
now=nex[now];
}
if(now==0)return -1;
return g[now];
}
};
struct suffix{
char a[maxn];
int n,m,sa[maxn],rank[maxn],cnt[maxn],height[maxn],f[maxn][15],lg[maxn];
struct zj{
int x,y,i;
}data[maxn],tmp[maxn];
void getsa(){
register int i,len;
n=strlen(a+1);m=128;
memset(cnt,0,sizeof(cnt));
memset(height,0,sizeof(height));
memset(sa,0,sizeof(sa));
memset(rank,0,sizeof(rank));
for(i=1;i<=n;i++)data[i]=tmp[i]=(zj){0,0,0};
for(i=1;i<=n;i++)cnt[a[i]]=1;
for(i=2;i<=m;i++)cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--)rank[i]=cnt[a[i]];
for(len=1;len<n;len<<=1){
for(i=1;i<=n;i++)data[i]=(zj){rank[i],rank[i+len],i};
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;i++)cnt[data[i].y]++;
for(i=1;i<=m;i++)cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--)tmp[cnt[data[i].y]--]=data[i];
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;i++)cnt[data[i].x]++;
for(i=1;i<=m;i++)cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--)data[cnt[tmp[i].x]--]=tmp[i];
for(i=1;i<=n;i++){
if(data[i].x==data[i-1].x&&data[i].y==data[i-1].y)rank[data[i].i]=rank[data[i-1].i];
else rank[data[i].i]=rank[data[i-1].i]+1;
}
if(rank[data[n].i]==n)break;
m=rank[data[n].i];
}
for(i=1;i<=n;i++)sa[rank[i]]=i;
}
void getheight(){
int k=0;
for(int i=1;i<=n;i++){
if(k)k--;
while(i+k<=n&&sa[rank[i]-1]+k<=n&&a[i+k]==a[sa[rank[i]-1]+k])k++;
height[rank[i]]=k;
}
}
void getst(){
lg[1]=0;
for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1;
for(int i=1;i<=n;i++)f[i-1][1]=height[i];
for(int j=2;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
int lcp(int l,int r){
if(l==r)return n-l+1;
l=rank[l];r=rank[r];
if(l>r)swap(l,r);
int k=lg[r-l+1];
return min(f[l][k],f[r-(1<<k)+1][k]);
}
};
后缀数组
struct suffix{
char a[maxn];
int n,sa[maxn],rank[maxn],cnt[maxn],height[maxn],f[maxn][15],lg[maxn];
struct zj{
int x,y,i;
}data[maxn],tmp[maxn];
void getsa(){
register int i,len;
n=strlen(a+1);
memset(cnt,0,sizeof(cnt));
memset(height,0,sizeof(height));
memset(sa,0,sizeof(sa));
memset(rank,0,sizeof(rank));
for(i=1;i<=n;i++)data[i]=tmp[i]=(zj){0,0,0};
for(i=1;i<=n;i++)cnt[a[i]]=1;
for(i=1;i<=128;i++)cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--)rank[i]=cnt[a[i]];
for(len=1;len<n;len<<=1){
for(i=1;i<=n;i++)data[i]=(zj){rank[i],rank[i+len],i};
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;i++)cnt[data[i].y]++;
for(i=1;i<=n;i++)cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--)tmp[cnt[data[i].y]--]=data[i];
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;i++)cnt[data[i].x]++;
for(i=1;i<=n;i++)cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--)data[cnt[tmp[i].x]--]=tmp[i];
for(i=1;i<=n;i++){
if(data[i].x==data[i-1].x&&data[i].y==data[i-1].y)rank[data[i].i]=rank[data[i-1].i];
else rank[data[i].i]=rank[data[i-1].i]+1;
}
if(rank[data[n].i]==n)break;
}
for(i=1;i<=n;i++)sa[rank[i]]=i;
}
void getheight(){
int k=0;
for(int i=1;i<=n;i++){
if(k)k--;
while(i+k<=n&&sa[rank[i]-1]+k<=n&&a[i+k]==a[sa[rank[i]-1]+k])k++;
height[rank[i]]=k;
}
}
void getst(){
lg[1]=0;
for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1;
for(int i=1;i<=n;i++)f[i-1][1]=height[i];
for(int j=2;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
int lcp(int l,int r){
if(l==r)return n-l+1;
l=rank[l];r=rank[r];
if(l>r)swap(l,r);
int k=lg[r-l+1];
return min(f[l][k],f[r-(1<<k)+1][k]);
}
};