int gcd(int a,int b)
{
return b == 0?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b; //先除后乘防止a*b溢出
}
void extgcd(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
if (!b)
{
x = 1;
y = 0;
}
else
{
extgcd(b,a%b,y,x);
y -= x*(a/b);
}
}
int m = sqrt(n+0.5);
memset(vis,0,sizeof(vis));
for (int i = 2; i <= m; i++)
{
if (!vis[i])
{
for (int j = i*i; j <= n; j += i)
{
vis[j] = 1;
}
}
}
版本二O(nloglogn)
int p = 0;
memset(is_prime,true,sizeof(is_prime));
is_prime[0] = is_prime[1] = false;
for(int i = 2; i <= MAX; i++)
{
if (is_prime[i])
{
prime[p++] = i;
for (int j = 2 * i; j <= MAX; j += i)
{
is_prime[j] = false;
}
}
}
对于不超过√m 的所有素数p,筛选区间[n,m]内p² 的所有倍数
LL mod_multi(LL x,LL y,LL mod) //拆分成y个x相加
{
LL res = 0;
while (y)
{
if (y&1)
{
res += x;
while (res >= mod) res -= mod;
}
x += x;
while (x >= mod) x -= mod;
y >>= 1;
}
return res;
}
LL mod_pow(LL x,LL n,LL mod)
{
LL res = 1;
while (n > 0)
{
if (n&1)
{
res = mod_mulit(res,x,mod);
// res = res*x%mod;
}
x = mod_multi(x,x,mod);
//x = x*x%mod;
n >>= 1;
}
return res;
}
// binsearch_min 返回key(可能有重复)第一次出现的下标,如无return -1
int binsearch_min(int * arr, int lef, int rig, int key)
{
if(!arr) return -1;
int left = lef, right = rig;
while(left < right)
{
int mid = left + ((right-left)>>1);
if(arr[mid] < key)
{
left = mid+1;
}
else
{
right = mid;
}
}
if(arr[left] == key) return left;
return -1;
}
// binsearch_max 返回key(可能有重复)最后一次出现的下标,如无return -1
int binsearch_max(int * arr, int lef, int rig, int key)
{
if(!arr) return -1;
int left = lef, right = rig;
while(left < right -1)
{
int mid = left + ((right-left)>>1);
if(arr[mid] <= key)
{
left = mid;
}
else
{
right = mid;
}
}
if(arr[right] == key) // 找max,先判断right
{
return right;
}
else if(arr[left] == key)
{
return left;
}
else
return -1;
}
void init()
{
memset(father,0,sizeof(father));
memset(rk,0,sizeof(rk));
for (int i = 0; i <= N; i++)
{
father[i] = i;
}
}
int find(int x)
{
int r = x;
while (father[r] != r)
{
r = father[r];
}
int i = x,j;
while (i != r) //路径压缩
{
j = father[i];
father[i] = r;
i = j;
}
return r;
}
/*
int find(int x)
{
return father[x] == x?father[x]:father[x] = find(father[x]);
}
*/
void unite(int x,int y)
{
int fx,fy;
fx = find(x);
fy = find(y);
if (fx == fy) return;
if (rk[fx] < rk[fy])
{
father[fx] = fy;
}
else
{
father[fy] = fx;
if (rk[fx] == rk[fy])
{
rk[fx]++;
}
}
}
void permutation(int n,int *A,int cur)
{
if (cur == n) //递归边界
{
for (int i = 0;i < n;i++) printf("%d ",A[i]);
printf("
");
}
else for (int i = 1;i <= n;i++) //尝试在A[cur}中填各种整数i
{
int ok = 1;
for (int j = 0;j < cur;j++) if (A[j] == i) ok = 0; //如果i已经在A[0]~A[cur-1]出现过,则不能再选
if (ok)
{
A[cur] = i;
permutation(n,A,cur+1); //递归调用
}
}
}
void permutation(int n,int *P,int *A,int cur) //输入数组P,并按字典序输出数组A各元素的所有全排列
{
if (cur == n)
{
for (int i = 0; i < n; i++) printf("%d ",A[i]);
printf("
");
}
else for (int i = 0; i < n; i++)
{
if (!i || P[i] != P[i-1])
{
int c1 = 0,c2 = 0;
for (int j = 0; j < cur; j++) if (A[j] == P[i]) c1++;
for (int j = 0; j < n; j++) if (P[i] == P[j]) c2++;
if (c1 < c2)
{
A[cur] = P[i];
permutation(n,P,A,cur+1);
}
}
}
}
/* 寻找有向图强连通分量的tarjan算法
* index表示的就是时间戳
* scc_cnt 表示强连通分量的个数
* belong[u] 表示结点u属于哪一个强连通分量
* inst[u] 表示结点u是否仍然在栈中
* st[] 和 top 分别表示栈和栈顶位置
*index = scc_cnt = top = 0*/
void targin(int u)
{
int v;
dfn[u] = low[u] = ++index;
st[++top] = u;
inst[u] = 1;
for (int i = head[u];i != -1;i = edge[i].next)
{
v = edge[i].v;
if (!dfn[v])
{
targin(v);
low[u] = min(low[u],low[v]);
}
else if (inst[v])
low[u] = min(low[u],dfn[v]);
}
if (low[u] == dfn[u])
{
scc_cnt++;
do
{
v = st[top--];
inst[v] = 0;
belong[v] = scc_cnt;
}
while (u != v);
}
}
/*
* tree[x].left 表示以 x 为节点的左儿子
* tree[x].right 表示以 x 为节点的右儿子
* tree[x].size 表示以 x 为根的节点的个数(大小)
*/
struct SBT
{
int key,left,right,size;
} tree[10010];
int root = 0,top = 0;
void left_rot(int &x) // 左旋
{
int y = tree[x].right;
if (!y) return;
tree[x].right = tree[y].left;
tree[y].left = x;
tree[y].size = tree[x].size;
tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1;
x = y;
}
void right_rot(int &x) //右旋
{
int y = tree[x].left;
if (!y) return;
tree[x].left = tree[y].right;
tree[y].right = x;
tree[y].size = tree[x].size;
tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1;
x = y;
}
void maintain(int &x,bool flag) //维护SBT状态
{
if (!x) return;
if (flag == false) //左边
{
if(tree[tree[tree[x].left].left].size > tree[tree[x].right].size)//左孩子的左孩子大于右孩子
right_rot(x);
else if (tree[tree[tree[x].left].right].size > tree[tree[x].right].size) //左孩子的右孩子大于右孩子
{
left_rot(tree[x].left);
right_rot(x);
}
else
return;
}
else //右边
{
if(tree[tree[tree[x].right].right].size > tree[tree[x].left].size)//右孩子的右孩子大于左孩子
left_rot(x);
else if(tree[tree[tree[x].right].left].size > tree[tree[x].left].size) //右孩子的左孩子大于左孩子
{
right_rot(tree[x].right);
left_rot(x);
}
else
return;
}
maintain(tree[x].left,false);
maintain(tree[x].right,true);
maintain(x,true);
maintain(x,false);
}
void insert(int &x,int key) //插入
{
if (x == 0)
{
x = ++top;
tree[x].left = 0;
tree[x].right = 0;
tree[x].size = 1;
tree[x].key = key;
}
else
{
tree[x].size++;
if(key < tree[x].key)
insert(tree[x].left,key);
else
insert(tree[x].right,key);//相同元素可插右子树
maintain(x,key >= tree[x].key);
}
}
int remove(int &x,int key) //利用后继删除
{
tree[x].size--;
if(key > tree[x].key)
remove(tree[x].right,key);
else if(key < tree[x].key)
remove(tree[x].left,key);
else if(tree[x].left !=0 && !tree[x].right) //有左子树,无右子树
{
int tmp = x;
x = tree[x].left;
return tmp;
}
else if(!tree[x].left && tree[x].right != 0) //有右子树,无左子树
{
int tmp = x;
x = tree[x].right;
return tmp;
}
else if(!tree[x].left && !tree[x].right) //无左右子树
{
int tmp = x;
x = 0;
return tmp;
}
else //左右子树都有
{
int tmp = tree[x].right;
while(tree[tmp].left)
tmp = tree[tmp].left;
tree[x].key = tree[temp].key;
remove(tree[x].right,tree[tmp].key);
}
}
int getmin(int x) //求最小值
{
while(tree[x].left)
x = tree[x].left;
return tree[x].key;
}
int getmax(int x) //求最大值
{
while(tree[x].right)
x = tree[x].right;
return tree[x].key;
}
int pred(int &x,int y,int key) //前驱,y初始前驱,从0开始, 最终要的是返回值的key值
{
if(x == 0)
return y;
if(key > tree[x].key)
return pred(tree[x].right,x,key);
else
return pred(tree[x].left,y,key);
}
int succ(int &x,int y,int key) //后继,同上
{
if(x == 0)
return y;
if(key < tree[x].key)
return succ(tree[x].left,x,key);
else
return succ(tree[x].right,y,key);
}
int select(int &x,int k) //查找第k小的数
{
int r = tree[tree[x].left].size + 1;
if(r == k)
return tree[x].key;
else if(r < k)
return select(tree[x].right,k - r);
else
return select(tree[x].left,k);
}
int rank(int &x,int key) //key排第几
{
if(key < tree[x].key)
{
return rank(tree[x].left,key);
}
else if(key > tree[x].key)
return rank(tree[x].right,key) + tree[tree[x].left].size + 1;
else
return tree[tree[x].left].size + 1;
}
ios::sync_with_stdio(false);
cin.tie(NULL);