SA
int sa[N],rk[N],oldrk[N<<1],id[N],cnt[N];
void calcSA(int n,int V){
int pos=0;
forUp(i,1,n)++cnt[rk[i]=s[i]];
forUp(i,1,V)cnt[i]+=cnt[i-1];
forDown(i,n,1)sa[cnt[rk[i]]--]=i;
for(int j=1;;j<<=1,V=pos){
int cur=0;
forUp(i,n-j+1,n)id[++cur]=i;
forUp(i,1,n)if(sa[i]>j)id[++cur]=sa[i]-j;
memset(cnt,0,sizeof(cnt));
forUp(i,1,n)++cnt[rk[i]];
forUp(i,1,V)cnt[i]+=cnt[i-1];
forDown(i,n,1)sa[cnt[rk[id[i]]]--]=id[i];
memcpy(oldrk,rk,sizeof(rk));
pos=0;
forUp(i,1,n){
if(oldrk[sa[i]]==oldrk[sa[i-1]]&&oldrk[sa[i]+j]==oldrk[sa[i-1]+j])rk[sa[i]]=pos;
else rk[sa[i]]=++pos;
}
if(pos==n)break;
}
}
Miller-Rabin
ll QuickPow(ll x,ll y,ll mod){
ll ans=1ll;
while(y){
if(y&1ll)ans=ans*x%mod;
x=x*x%mod;
y>>=1ll;
}
return ans;
}
bool MillerRabin(ll n){
if(n<3ll||!(n&1))return n==2;
if(n%3==0)return n==3;
const int test_time=7;
const ll a[7]={2ll,325ll,9375ll,28178ll,450775ll,9780504ll,1795265022ll};
ll p=n-1ll,q=0ll;
while(!(p&1))p>>=1,++q;
for(int i=0;i<test_time;++i){
if(a[i]%n==0ll||a[i]%n==1ll||a[i]%n==n-1ll)continue;
ll ans=QuickPow(a[i]%n,p,n);
if(ans==1ll)continue;
int j;
for(j=0;j<q;++j){
if(ans==n-1ll)break;
ans=ans*ans%n;
}
if(j==q)return false;
}
return true;
}
NTT
constexpr ull mod=998244353,G=3,invG=332748118;int rev[LIM];
ull qp(ull x,ull y){ull ans=1;for(;y;y>>=1,x=x*x%mod)if(y&1)ans=ans*x%mod;return ans;}
ull F[LIM],prod[LIM]={1},tmp;
void NTT(int lim,int *f,bool opt){
static bool first=true;
if(first){
first=false;
forUP(i,1,lim)rev[i]=(rev[i>>1]>>1)|(i&1?lim>>1:0);
}
forUP(i,0,lim)F[i]=f[rev[i]];
for(int k=1;k<lim;k<<=1){
ull tG=qp(opt?invG:G,(mod-1)/(k<<1));
forUP(i,1,k)prod[i]=prod[i-1]*tG%mod;
for(int i=0;i<lim;i+=k<<1){
for(int j=0;j<k;++j){
tmp=prod[j]*F[i|j|k]%mod;
F[i|j|k]=F[i|j]+mod-tmp;
F[i|j]+=tmp;
}
}
if(k==(1<<17))forUP(i,0,lim)F[i]%=mod;
}
if(opt){
ull INV=qp(lim,mod-2);
forUP(i,0,lim)f[i]=F[i]*INV%mod;
}
else forUP(i,0,lim)f[i]=F[i]%mod;
}
FWT
enum{OR,AND,XOR};
void FWT(int n,ll *arr,int type,bool inv){
switch(type){
case OR:
for(int len=2;len<=n;len<<=1){
int k=len>>1;
for(int i=0;i<n;i+=len)for(int j=0;j<k;++j)(arr[i+j+k]+=inv?mod-arr[i+j]:arr[i+j])%=mod;
}break;
case AND:
for(int len=2;len<=n;len<<=1){
int k=len>>1;
for(int i=0;i<n;i+=len)for(int j=0;j<k;++j)(arr[i+j]+=inv?mod-arr[i+j+k]:arr[i+j+k])%=mod;
}break;
case XOR:
for(int len=2;len<=n;len<<=1){
int k=len>>1;
for(int i=0;i<n;i+=len)for(int j=0;j<k;++j){
(arr[i+j]+=arr[i+j+k])%=mod;
(arr[i+j+k]=(arr[i+j]-(arr[i+j+k]<<1))%mod)<0?arr[i+j+k]+=mod:0;
(arr[i+j]*=inv?inv2:1)%=mod;
(arr[i+j+k]*=inv?inv2:1)%=mod;
}
}break;
}
}
Link-Cut Tree
int fa[N],son[N][2];bool rev[N];
bool nroot(int node){return son[fa[node]][0]==node||son[fa[node]][1]==node;}
void pushup(int node){
//pushup
}
void modifyRev(int node){
rev[node]^=1;
swap(son[node][0],son[node][1]);
}
void pushdown(int node){
if(rev[node]){
if(son[node][0])modifyRev(son[node][0]);
if(son[node][1])modifyRev(son[node][1]);
rev[node]=0;
}
//other modify
}
void rotate(int node){
int father=fa[node],grand=fa[father],dir=son[father][1]==node,tmp=son[node][!dir];
if(nroot(father))son[grand][son[grand][1]==father]=node;
son[node][!dir]=father,son[father][dir]=tmp;
if(tmp)fa[tmp]=father;
fa[father]=node,fa[node]=grand;
pushup(father);pushup(node);
}
void clearTag(int node){
if(nroot(node))clearTag(fa[node]);
pushdown(node);
}
void splay(int node){
clearTag(node);
while(nroot(node)){
int father=fa[node],grand=fa[father];
if(nroot(father))rotate((son[father][0]==node)^(son[grand][0]==father)?node:father);
rotate(node);
}
pushup(node);
}
int access(int node){
int tmp=0;
for(;node;node=fa[tmp=node])splay(node),son[node][1]=tmp,pushup(node);
return tmp;
}
void makeRoot(int node){
access(node);splay(node);
modifyRev(node);
}
int findRoot(int node){
access(node);splay(node);
while(son[node][0])pushdown(node),node=son[node][0];
splay(node);
return node;
}
void split(int node1,int node2){
makeRoot(node1);
access(node2);splay(node2);
}
void link(int node1,int node2){
makeRoot(node1);
if(findRoot(node2)!=node1)makeRoot(node2),fa[node1]=node2;
}
void cut(int node1,int node2){
makeRoot(node1);
if(findRoot(node2)==node1&&fa[node2]==node1&&!son[node2][0]){
fa[node2]=son[node1][1]=0;
pushup(node1);
}
}
Dinic
struct edge{int to,nxt,cap,flow;}e[M];int cnt,head[N];
int dep[N],cur[N];ll maxflow;
void init(){maxflow=cnt=0;memset(head,-1,sizeof(head));}
void addEdge(int u,int v,int c){
e[cnt]=(edge){v,head[u],c,0};head[u]=cnt++;
e[cnt]=(edge){u,head[v],0,0};head[v]=cnt++;
}
bool bfs(int S,int T){
queue<int> q;
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(cur));
dep[S]=1;q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if(!dep[v]&&e[i].cap>e[i].flow){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[T];
}
int dfs(int T,int u,int flow){
if(u==T||!flow)return flow;
int ans=0;
for(int &i=cur[u];~i;i=e[i].nxt){
int v=e[i].to,delta;
if(dep[v]==dep[u]+1&&(delta=dfs(T,v,min(flow-ans,e[i].cap-e[i].flow)))){
ans+=delta;
e[i].flow+=delta;
e[i^1].flow-=delta;
if(ans==flow)break;
}
}
return ans;
}
void dinic(int S,int T){
while(bfs(S,T))maxflow+=dfs(T,S,INF);
}
SSP
struct edge{int to,nxt,cap,cost,flow;}e[M];int cnt,head[N];
int cur[N];ll dis[N],maxflow,mincost;bool vis[N];
void init(){cnt=maxflow=mincost=0;memset(head,-1,sizeof(head));}
void addEdge(int u,int v,int cap,int cost){
e[cnt]={v,head[u],cap,cost,0};head[u]=cnt++;
e[cnt]={u,head[v],0,-cost,0};head[v]=cnt++;
}
bool SPFA(int S,int T,bool flag){
queue<int> q;
if(flag)memset(dis,0x3f,sizeof(dis));
else memset(dis,0xcf,sizeof(dis));
memcpy(cur,head,sizeof(cur));
q.push(S),dis[S]=0,vis[S]=true;
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=false;
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if(((flag&&dis[v]>dis[u]+e[i].cost)||(!flag&&dis[v]<dis[u]+e[i].cost))&&e[i].cap>e[i].flow){
dis[v]=dis[u]+e[i].cost;
if(!vis[v]){
q.push(v);
vis[v]=true;
}
}
}
}
return flag?dis[T]!=INFLL:dis[T]!=MINFLL;
}
int dfs(int T,int u,int flow){
if(u==T||!flow)return flow;
int ans=0;
vis[u]=true;
for(int &i=cur[u];~i;i=e[i].nxt){
int v=e[i].to,delta;
if(!vis[v]&&dis[v]==dis[u]+e[i].cost&&(delta=dfs(T,v,min(flow-ans,e[i].cap-e[i].flow)))){
ans+=delta;
e[i].flow+=delta;
e[i^1].flow-=delta;
mincost+=delta*e[i].cost;
if(ans==flow)break;
}
}
vis[u]=false;
return ans;
}
void SSP(int S,int T,bool flag=true){
int flow;
while(SPFA(S,T,flag))while((flow=dfs(T,S,INF)))maxflow+=flow;
}
fastIO
namespace LXcjh4998{
namespace internal{namespace type_traits{
template<class _Tp>using __is_signed_int128=typename std::conditional<std::is_same<_Tp,__int128_t>::value||std::is_same<_Tp,__int128>::value,std::true_type,std::false_type>::type;
template<class _Tp>using __is_unsigned_int128=typename std::conditional<std::is_same<_Tp,__uint128_t>::value||std::is_same<_Tp,unsigned __int128>::value,std::true_type,std::false_type>::type;
template<class _Tp>using __make_unsigned_int128=typename std::conditional<std::is_same<_Tp,__int128_t>::value,__uint128_t,unsigned __int128>;
template<class _Tp>using __is_integer=typename std::conditional<std::is_integral<_Tp>::value||__is_signed_int128<_Tp>::value||__is_unsigned_int128<_Tp>::value,std::true_type,std::false_type>::type;
template<class _Tp>using __is_signed_integer=typename std::conditional<(__is_integer<_Tp>::value&&std::is_signed<_Tp>::value)||__is_signed_int128<_Tp>::value,std::true_type,std::false_type>::type;
template<class _Tp>using __is_unsigned_integer=typename std::conditional<(__is_integer<_Tp>::value&&std::is_unsigned<_Tp>::value)||__is_unsigned_int128<_Tp>::value,std::true_type,std::false_type>::type;
template<class _Tp>using __to_unsigned=typename std::conditional<__is_signed_int128<_Tp>::value,__make_unsigned_int128<_Tp>,typename std::conditional<std::is_signed<_Tp>::value,std::make_unsigned<_Tp>,std::common_type<_Tp>>::type>::type;
template<class _Tp>using __is_signed_integer_type=std::enable_if_t<__is_signed_integer<_Tp>::value>;
template<class _Tp>using __is_unsigned_integer_type=std::enable_if_t<__is_unsigned_integer<_Tp>::value>;
template<class _Tp>using __to_unsigned_type=typename __to_unsigned<_Tp>::type;
}using namespace type_traits;namespace check_char_type{bool __is_digit(const char &c){return 48<=c&&c<=57;}bool __is_not_blank(const char &c){return c^32&&c^10&&c^13&&c&&~c;}}using namespace check_char_type;}
namespace fastIO{
struct istream{void tie([[maybe_unused]]int x){}}fin;struct ostream{void tie([[maybe_unused]]int x){}}fout;
constexpr int __maxn=1<<20;char __in[__maxn],__out[__maxn],*__p1=__in,*__p2=__in,*__p3=__out;
#define getchar() (__p1==__p2&&(__p2=(__p1=__in)+fread(__in,1,__maxn,stdin),__p1==__p2)?EOF:*__p1++)
#define flush() (fwrite(__out,1,__p3-__out,stdout))
#define putchar(ch) (__p3==__out+__maxn&&(flush(),__p3=__out),*__p3++=(ch))
class __flush{public:~__flush(){flush();}}__var_to_flush;
template<typename _Tp,internal::__is_signed_integer_type<_Tp>* =nullptr>istream& operator>>(istream &fin,_Tp &x){x=0;bool flag(false);char ch=getchar();while(!internal::__is_digit(ch))flag^=!(ch^45),ch=getchar();while(internal::__is_digit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();flag?x=-x:x;return fin;}
template<typename _Tp,internal::__is_unsigned_integer_type<_Tp>* =nullptr>istream& operator>>(istream &fin,_Tp &x){x=0;char ch=getchar();while(!internal::__is_digit(ch))ch=getchar();while(internal::__is_digit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return fin;}
istream& operator>>(istream &fin,char &x){do x=getchar();while(!internal::__is_not_blank(x));return fin;}
istream& operator>>(istream &fin,char *x){char ch=getchar();do *(x++)=ch;while(internal::__is_not_blank(ch=getchar()));return fin;}
istream& operator>>(istream &fin,std::string &x){char ch=getchar();x.clear();do x+=ch;while(internal::__is_not_blank(ch=getchar()));return fin;}
template<typename _Tp,internal::__is_unsigned_integer_type<_Tp>* =nullptr>ostream& operator<<(ostream &fout,_Tp x){int stk[50],tp(0);do stk[++tp]=x%10,x/=10;while(x);while(tp)putchar(stk[tp--]|48);return fout;}
template<typename _Tp,internal::__is_signed_integer_type<_Tp>* =nullptr>ostream& operator<<(ostream &fout,_Tp x){internal::__to_unsigned_type<_Tp> tmp=x<0?(putchar(45),-x):x;fout<<tmp;return fout;}
ostream& operator<<(ostream &fout,const char &x){putchar(x);return fout;}
template<typename _Tp>ostream& operator<<(ostream &fout,_Tp *x){while(*x)putchar(*(x++));return fout;}
ostream& operator<<(ostream &fout,const std::string &x){for(const char &ch:x)putchar(ch);return fout;}
#undef getchar
#undef putchar
#undef flush
#define cin LXcjh4998::fin
#define cout LXcjh4998::fout
}using namespace fastIO;}
DS::Treap
namespace LXcjh4998{namespace DS{namespace Treap{
template<class _Tp,int (*rand)(void),_Tp min_value,_Tp max_value>
struct treap{
private:int tot,rt;std::vector<int> lson,rson,cnt,rnd,sz;std::vector<_Tp> val;
inline void pushup(int node){sz[node]=sz[lson[node]]+sz[rson[node]]+cnt[node];}
inline void lrotate(int &node){int tmp=rson[node];rson[node]=lson[tmp];lson[tmp]=node;sz[tmp]=sz[node];pushup(node);node=tmp;}
inline void rrotate(int &node){int tmp=lson[node];lson[node]=rson[tmp];rson[tmp]=node;sz[tmp]=sz[node];pushup(node);node=tmp;}
void insert(int &node,const _Tp &value){if(!node){node=++tot;val[node]=value;cnt[node]=sz[node]=1;rnd[node]=rand();return;}++sz[node];if(val[node]==value)++cnt[node];else if(value<val[node]){insert(lson[node],value);if(rnd[lson[node]]<rnd[node])rrotate(node);}else{insert(rson[node],value);if(rnd[rson[node]]<rnd[node])lrotate(node);}}
bool remove(int &node,const _Tp &value){if(!node)return false;if(val[node]==value){if(cnt[node]>1){--sz[node],--cnt[node];return true;}if(!lson[node]||!rson[node]){node=lson[node]|rson[node];return true;}if(rnd[lson[node]]<rnd[rson[node]])rrotate(node);else lrotate(node);return remove(node,value);}else if(value<val[node]){bool success=remove(lson[node],value);if(success)--sz[node];return success;}else{bool success=remove(rson[node],value);if(success)--sz[node];return success;}}
public:
treap():tot(0),rt(0){}
treap(int n):tot(0),rt(0),lson(n+1),rson(n+1),cnt(n+1),rnd(n+1),sz(n+1),val(n+1){}
void insert(const _Tp &value){insert(rt,value);}
bool remove(const _Tp &value){return remove(rt,value);}
int query_rank(const _Tp &value){int cur=rt,rank=0;for(;cur;){if(val[cur]==value)return rank+sz[lson[cur]]+1;else if(value<val[cur])cur=lson[cur];else rank+=sz[lson[cur]]+cnt[cur],cur=rson[cur];}return rank+1;}
_Tp query_by_rank(int rank){assert(1<=rank&&rank<=sz[rt]);int cur=rt;for(;rank<=sz[lson[cur]]||sz[lson[cur]]+cnt[cur]<rank;){if(rank<=sz[lson[cur]])cur=lson[cur];else rank-=sz[lson[cur]]+cnt[cur],cur=rson[cur];}return val[cur];}
_Tp query_prev(const _Tp &value){int cur=rt,res=0;for(;cur;){if(val[cur]<value)res=cur,cur=rson[cur];else cur=lson[cur];}return res?val[res]:min_value;}
_Tp query_next(const _Tp &value){int cur=rt,res=0;for(;cur;){if(val[cur]>value)res=cur,cur=lson[cur];else cur=rson[cur];}return res?val[res]:max_value;}
};
}using namespace Treap;}}