Logo wfirstzhang 的博客

博客

【Repo】一个可以部分替代 windows fc / linux diff 的程序

tokencmp

#include <cassert>
#include <cstdio>
#include <fstream>
#include <string>

int main(int argc, char** argv) {
    using namespace std;
    assert(argc == 3);
    ifstream in1(argv[1]);
    ifstream in2(argv[2]);
    string token1, token2;
    int cnt1 = 0, cnt2 = 0;
    while(true)
    {
        int tmp = cnt1; 
        cnt1 += bool(in1 >> token1);
        cnt2 += bool(in2 >> token2);
        if(cnt1 != cnt2 || tmp == cnt1)
            break;
        if(token1 != token2)
        {
            printf("wrong answer\nWrong answer on token %d, %s read %s, %s read %s.\n",
                cnt1, argv[1], token1.c_str(), argv[2], token2.c_str());
            return 17;
        }
    }
    if(cnt1 < cnt2)
    {
        printf("wrong answer\nFile %s too short.\n", argv[1]);
        return 18; 
    }
    if(cnt2 < cnt1)
    {
        printf("wrong answer\nFile %s too short.\n", argv[2]);
        return 19; 
    }
    printf("ok %d tokens.\n", cnt1); 
    return 0;
}

nlsnel_fcmp

#include <cassert>
#include <cstdio>
#include <fstream>
#include <string>

int main(int argc, char** argv) {
    using namespace std;
    assert(argc == 3);
    ifstream in1(argv[1]);
    ifstream in2(argv[2]);
    string token1, token2;
    int cnt1 = 0, cnt2 = 0;
    while(true)
    {
        int tmp = cnt1; 
        cnt1 += bool(getline(in1, token1));
        cnt2 += bool(getline(in2, token2));
        if(cnt1 != cnt2 || tmp == cnt1)
            break;
        while(!token1.empty() && token1.back() == ' ')
            token1.pop_back();
        while(!token2.empty() && token2.back() == ' ')
            token2.pop_back();
        if(token1 != token2)
        {
            printf("wrong answer\nWrong answer on token %d, %s read %s, %s read %s.\n",
                cnt1, argv[1], token1.c_str(), argv[2], token2.c_str());
            return 17;
        }
    }
    if(cnt1 < cnt2)
    {
        printf("wrong answer\nFile %s too short.\n", argv[1]);
        return 18; 
    }
    if(cnt2 < cnt1)
    {
        printf("wrong answer\nFile %s too short.\n", argv[2]);
        return 19; 
    }
    printf("ok %d tokens.\n", cnt1); 
    return 0;
}

nlsnel_fcmp(testlib

#include "testlib.h"
#include <string>
#include <vector>
#include <sstream>

using namespace std;

bool compareWords(const string& a, const string& b) {
    vector<string> va, vb;
    stringstream sa;

    sa << a;
    string cur;
    while (sa >> cur)
        va.push_back(cur);

    stringstream sb;
    sb << b;
    while (sb >> cur)
        vb.push_back(cur);

    return (va == vb);
}

int main(int argc, char *argv[]) {
    setName("逐行比较 tokens");
    registerTestlibCmd(argc, argv);

    string strAnswer;

    int n = 0;
    while (!ans.eof()) {
        std::string j = ans.readString();

        if (j.empty() && ans.eof())
            break;

        string p = ouf.readString();
        strAnswer = p;

        n++;

        if (!compareWords(j, p))
            quitf(_wa, "第 %d 行不同 - 答案是 '%s',但是读取到 '%s'.", n,
                  compress(j).c_str(), compress(p).c_str());
    }

    if (n == 1)
        quitf(_ok, "一行 '%s'.", compress(strAnswer).c_str());

    quitf(_ok, "共 %d 行.", n);
}

floatcmp

#include <cassert>
#include <cmath>
#include <cstdio>
#include <fstream>

constexpr long double Eps = 1e-2;

int main(int argc, char** argv) {
    using namespace std;
    assert(argc == 3);
    ifstream in1(argv[1]);
    ifstream in2(argv[2]);
    long double token1, token2;
    int cnt1 = 0, cnt2 = 0;
    while(true)
    {
        int tmp = cnt1; 
        cnt1 += bool(in1 >> token1);
        cnt2 += bool(in2 >> token2);
        if(cnt1 != cnt2 || tmp == cnt1)
            break;
        if(abs(token1 - token2) > Eps)
        {
            printf("wrong answer\nWrong answer on token %d, %Lf %Lf.\n",
                cnt1, token1, token2);
            return 17;
        }
    }
    if(cnt1 < cnt2)
    {
        printf("wrong answer\nFile %s too short.\n", argv[1]);
        return 18; 
    }
    if(cnt2 < cnt1)
    {
        printf("wrong answer\nFile %s too short.\n", argv[2]);
        return 19; 
    }
    printf("ok %d tokens.\n", cnt1); 
    return 0;
}

use(windows)

可执行文件名称 输出文件名1 输出文件名2

自动测大样例(builtin_checker)

#include <cassert>
#include <cstdio>
#include <ctime>
#include <fstream>
#include <string>

#ifdef _WIN32
#define COPY_COMMAND "copy"
#define REMOVE_COMMAND "del"
#define RUN_PREFIX ""
#else
#define COPY_COMMAND "cp"
#define REMOVE_COMMAND "rm"
#define RUN_PREFIX "./"
#endif

// 标准输入输出控制标志,文件输入输出请注释掉 
#define STDIO

// 输入后缀 
#define INF_SUF "in"
// 输出后缀 
#define OUF_SUF "out"
// 答案后缀 
#define ANS_SUF "ans"
// 从第几个大样例开始测试 
#define TEST_START 1 

// 默认你可执行文件名等于题目名称 
// argv[1] 是可执行文件名,大样例没有前缀,argv[2]是大样例数目 
// argv[1] 是可执行文件名,大样例前缀是 argv[3],argv[2]是大样例数目 

// 用法两种
// 1. (./)本程序名 题目名称 要测试的大样例数量
// 2. (./)本程序名 题目名称 要测试的大样例数量 大样例前缀 

int builtin_checker(std::string ouf, std::string ans);

int main(int argc, char** argv) {
    using namespace std;
    string title = argv[1], pre = "";
    int cnt = stoi(argv[2]);
    if(argc == 4)
        pre = argv[3];
    for(int i = TEST_START; i < TEST_START + cnt; i++)
    {
        system((COPY_COMMAND " " + pre + to_string(i) + "." INF_SUF  " " + title + "." INF_SUF).c_str());
        auto start = clock();
#ifdef STDIO
        system((RUN_PREFIX + title + " < " + title + "." INF_SUF " >" + title + "." OUF_SUF).c_str());
#else
        system((RUN_PREFIX + title).c_str());
#endif
        double time = double(clock() - start) / CLOCKS_PER_SEC;
        printf("%f s ", time);
        if(builtin_checker(title + "." OUF_SUF, pre + to_string(i) + "." ANS_SUF))
            return 16;
        system((REMOVE_COMMAND " " + title + "." INF_SUF).c_str()); 
    }
    return 0;
}

int builtin_checker(std::string ouf, std::string ans) {
    using namespace std;
    ifstream in1(ouf);
    ifstream in2(ans);
    string token1, token2;
    int cnt1 = 0, cnt2 = 0;
    while(true)
    {
        int tmp = cnt1; 
        cnt1 += bool(getline(in1, token1));
        cnt2 += bool(getline(in2, token2));
        if(cnt1 != cnt2 || tmp == cnt1)
            break;
        while(!token1.empty() && token1.back() == ' ')
            token1.pop_back();
        while(!token2.empty() && token2.back() == ' ')
            token2.pop_back();
        if(token1 != token2)
        {
            printf("wrong answer\nWrong answer on token %d, %s read %s, %s expected %s.\n",
                cnt1, ouf.c_str(), token1.c_str(), ans.c_str(), token2.c_str());
            return 17;
        }
    }
    if(cnt1 < cnt2)
    {
        printf("wrong answer\nFile %s too short.\n", ouf.c_str());
        return 18; 
    }
    if(cnt2 < cnt1)
    {
        printf("wrong answer\nFile %s too long.\n", ouf.c_str());
        return 19; 
    }
    printf("ok %d tokens.\n", cnt1); 
    return 0;
}

定制版

lxn checker

全自动测大样例(linux,需配套chk)

#include <cassert>
#include <chrono>
#include <cstdio>
#include <string>

// 大样例前缀(去掉题目名称)
#define SAMPLE_PREFIX ""
// 工作目录
#define WORK_DIR "cmake-build-debug"
// 运行命令
#define RUN_COMMAND "cd " WORK_DIR "&& ./OI_project_main"
// checker
#define CHECKER "./chk"
// 输入、输出、答案后缀
#define INPUT_SUFFIX ".in"
#define OUTPUT_SUFFIX ".out"
#define ANSWER_SUFFIX ".ans"
// 标准输入输出请启用这个
#define STDIO

// ./run_checks 数据点个数 数据点目录(题目名称)

void exit_fail(int ret) {
    if (ret)
        exit(ret);
}

int main(int argc, char** argv) {
    using namespace std;
    assert(argc == 3);
    int cases = stoi(argv[1]);
    string probtitle = argv[2];
    printf("%s [%d cases]\n", probtitle.c_str(), cases);
    for (int i = 1; i <= cases; i++)
    {
        printf("\nRunning test %d\n", i);
        string ex_prefix = probtitle + "/" SAMPLE_PREFIX + probtitle + to_string(i);
        system(("cp " + ex_prefix + INPUT_SUFFIX " " WORK_DIR "/" + probtitle + INPUT_SUFFIX).c_str());
        auto start = chrono::high_resolution_clock::now();
#ifdef STDIO
        exit_fail(system(
            (RUN_COMMAND " < " + probtitle + INPUT_SUFFIX + " > " + probtitle + OUTPUT_SUFFIX).c_str()));
#else
        exit_fail(system(RUN_COMMAND));
#endif
        auto now = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start);
        printf(" %.3fs ", now.count() / 1e3);
        exit_fail(system((CHECKER " " WORK_DIR "/" + probtitle + OUTPUT_SUFFIX + " " + ex_prefix + ANSWER_SUFFIX).c_str()));
        system(("rm " WORK_DIR "/" + probtitle + ".in").c_str());
        system(("rm " WORK_DIR "/" + probtitle + ".out").c_str());
    }
    return 0;
}

全自动测大样例(linux,配套 3 参数 chk)

#include <cassert>
#include <chrono>
#include <cstdio>
#include <string>

// 大样例前缀(去掉题目名称)
#define SAMPLE_PREFIX ""
// 工作目录
#define WORK_DIR "cmake-build-debug"
// 运行命令
#define RUN_COMMAND "cd " WORK_DIR "&& ./OI_project_main"
// checker
#define CHECKER "./chk"
// 输入、输出、答案后缀
#define INPUT_SUFFIX ".in"
#define OUTPUT_SUFFIX ".out"
#define ANSWER_SUFFIX ".ans"
// 标准输入输出请启用这个
#define STDIO

// ./run_checks 数据点个数 数据点目录(题目名称)

void exit_fail(int ret) {
    if (ret)
        exit(ret);
}

int main(int argc, char** argv) {
    using namespace std;
    assert(argc == 3);
    int cases = stoi(argv[1]);
    string probtitle = argv[2];
    printf("%s [%d cases]\n", probtitle.c_str(), cases);
    for (int i = 1; i <= cases; i++)
    {
        printf("\nRunning test %d\n", i);
        string ex_prefix = probtitle + "/" SAMPLE_PREFIX + probtitle + to_string(i);
        system(("cp " + ex_prefix + INPUT_SUFFIX " " WORK_DIR "/" + probtitle + INPUT_SUFFIX).c_str());
        auto start = chrono::high_resolution_clock::now();
#ifdef STDIO
        exit_fail(system(
            (RUN_COMMAND " < " + probtitle + INPUT_SUFFIX + " > " + probtitle + OUTPUT_SUFFIX).c_str()));
#else
        exit_fail(system(RUN_COMMAND));
#endif
        auto now = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start);
        printf(" %.3fs ", now.count() / 1e3);
        exit_fail(system((CHECKER " " + ex_prefix + INPUT_SUFFIX " " WORK_DIR "/" + probtitle + OUTPUT_SUFFIX + " " + ex_prefix + ANSWER_SUFFIX).c_str()));
        system(("rm " WORK_DIR "/" + probtitle + ".in").c_str());
        system(("rm " WORK_DIR "/" + probtitle + ".out").c_str());
    }
    return 0;
}

全自动测大样例(linux,配套 3 参数 chk,带内存)[AI]

#include <cassert>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <vector>
#include <sys/resource.h>
#include <sys/wait.h>

// ====================== 配置 ======================
#define SAMPLE_PREFIX ""
#define WORK_DIR "cmake-build-debug"
#define RUN_BINARY "./OI_project_main"
#define CHECKER "./chk"
#define INPUT_SUFFIX ".in"
#define OUTPUT_SUFFIX ".out"
#define ANSWER_SUFFIX ".ans"
// 如果使用 STDIN/STDOUT 则启用
#define STDIO
// =================================================

void exit_fail(int ret) {
    if (ret) exit(ret);
}

/**
 * 运行程序并测量时间与内存占用
 * - input_path: 输入文件(用于 STDIO 模式)
 * - output_path: 输出文件(用于 STDIO 模式)
 * - bin_args: 可执行文件相对 WORK_DIR 的运行参数(用于文件 I/O 模式)
 *
 * 返回 (wall_time_ms, max_memory_kb)
 */
std::pair<long long, long long> run_and_measure(
    const std::string& input_path,
    const std::string& output_path,
    const std::vector<std::string>& bin_args
) {
    using namespace std;

    auto start = chrono::steady_clock::now();

    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork");
        exit(1);
    }

    if (pid == 0)
    {
        // 子进程
        if (chdir(WORK_DIR) != 0)
        {
            perror("chdir");
            exit(1);
        }

#ifdef STDIO
        // STDIN/STDOUT 重定向
        if (!input_path.empty())
        {
            freopen(input_path.c_str(), "r", stdin);
        }
        if (!output_path.empty())
        {
            freopen(output_path.c_str(), "w", stdout);
        }

        // 构造 exec 参数
        std::vector<char*> args;
        args.push_back(const_cast<char*>(RUN_BINARY));
        args.push_back(nullptr);

        execvp(args[0], args.data());

#else
        // 文件 I/O 模式:直接传递参数,不做重定向
        // 构造 exec 参数
        std::vector<char*> args;
        args.push_back(const_cast<char*>(RUN_BINARY));
        for (auto &s : bin_args)
            args.push_back(const_cast<char*>(s.c_str()));
        args.push_back(nullptr);

        execvp(args[0], args.data());
#endif

        perror("execvp");
        exit(1);
    }

    // 父进程:等待子进程并收集 rusage
    int status;
    struct rusage usage{};
    wait4(pid, &status, 0, &usage);

    auto end = chrono::steady_clock::now();
    long long ms = chrono::duration_cast<chrono::milliseconds>(end - start).count();
    long long mem = usage.ru_maxrss;

    return {ms, mem};
}

int main(int argc, char** argv) {
    using namespace std;

    assert(argc == 3);
    int cases = stoi(argv[1]);
    string probtitle = argv[2];

    printf("%s [%d cases]\n", probtitle.c_str(), cases);

    for (int i = 1; i <= cases; i++)
    {
        printf("\nRunning test %d\n", i);

        string prefix = probtitle + "/" SAMPLE_PREFIX + probtitle + to_string(i);
        string in_path = prefix + INPUT_SUFFIX;
        string ans_path = prefix + ANSWER_SUFFIX;

        string local_in = WORK_DIR "/" + probtitle + INPUT_SUFFIX;
        string local_out = WORK_DIR "/" + probtitle + OUTPUT_SUFFIX;

        // 复制输入文件到工作目录/题目.in
        system(("cp " + in_path + " " + local_in).c_str());

#ifdef STDIO

        // 测试运行(STDIO 模式)
        auto [time_ms, mem] = run_and_measure(
            probtitle + INPUT_SUFFIX,
            probtitle + OUTPUT_SUFFIX,
            {}
        );

#else
        std::vector<std::string> args{};

        auto [time_ms, mem] = run_and_measure(
            "", "",  // 不用 STDIO
            args
        );
#endif

        printf("%.3fs, %.3fMB\n", time_ms / 1e3, mem / 1048576.0);
        // Checker
        exit_fail(system(
            (CHECKER " " + local_in + " " + local_out + " " + ans_path).c_str()
        ));
        system(("rm " + local_in).c_str());
        system(("rm " + local_out).c_str());
    }

    return 0;
}

洛谷题单转vjudge题单

使用方法:洛谷题单左下角多选,右下角导出 $\texttt{T}$纯题号,输入进去会输出 vjudge 题单格式。

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

int main() {
    using namespace std;
    string src;
    cin >> src;
    src.push_back(',');
    string tmp;
    vector<string> set;
    for(auto ch : src)
        if(ch == ',')
        {
            set.push_back(tmp); 
            tmp.clear();
        }
        else
            tmp.push_back(ch);
    sort(set.begin(), set.end());
    for(const auto& i : set)
    {
        cout << "[problem:";
        if(i.size() > 2 && i.substr(0, 2) == "AT")
            cout << "AtCoder-" << i.substr(3);
        else if(i.size() > 1 && i.substr(0, 2) == "CF")
            cout << "CodeForces-" << i.substr(2);
        else if(i.size() > 2 && i.substr(0, 3) == "UVA")
            cout << "UVA-" << i.substr(3);
        else
            cout << "洛谷-" << i;
        cout << "]\n";
    }  
    return 0;
}

高精度模板

/* mini-gmp, a minimalistic implementation of a GNU GMP subset.

   Contributed to the GNU project by Niels M枚ller
   Additional functionalities and improvements by Marco Bodrato.

Copyright 1991-1997, 1999-2022 Free Software Foundation, Inc.

This file is part of the GNU MP Library.

The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of either:

  * the GNU Lesser General Public License as published by the Free
    Software Foundation; either version 3 of the License, or (at your
    option) any later version.

or

  * the GNU General Public License as published by the Free Software
    Foundation; either version 2 of the License, or (at your option) any
    later version.

or both in parallel, as here.

The GNU MP Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received copies of the GNU General Public License and the
GNU Lesser General Public License along with the GNU MP Library.  If not,
see https://www.gnu.org/licenses/.  */

/* NOTE: All functions in this file which are not declared in
   mini-gmp.h are internal, and are not intended to be compatible
   with GMP or with future versions of mini-gmp. */

/* Much of the material copied from GMP files, including: gmp-impl.h,
   longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
   mpn/generic/lshift.c, mpn/generic/mul_1.c,
   mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
   mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
   mpn/generic/submul_1.c. */

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* mini-gmp, a minimalistic implementation of a GNU GMP subset.

Copyright 2011-2015, 2017, 2019-2021 Free Software Foundation, Inc.

This file is part of the GNU MP Library.

The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of either:

  * the GNU Lesser General Public License as published by the Free
    Software Foundation; either version 3 of the License, or (at your
    option) any later version.

or

  * the GNU General Public License as published by the Free Software
    Foundation; either version 2 of the License, or (at your option) any
    later version.

or both in parallel, as here.

The GNU MP Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received copies of the GNU General Public License and the
GNU Lesser General Public License along with the GNU MP Library.  If not,
see https://www.gnu.org/licenses/.  */

/* About mini-gmp: This is a minimal implementation of a subset of the
   GMP interface. It is intended for inclusion into applications which
   have modest bignums needs, as a fallback when the real GMP library
   is not installed.

   This file defines the public interface. */

#ifndef __MINI_GMP_H__
#define __MINI_GMP_H__

/* For size_t */
#include <stddef.h>

#if defined (__cplusplus)
extern "C" {
#endif

void mp_set_memory_functions (void *(*) (size_t),
                  void *(*) (void *, size_t, size_t),
                  void (*) (void *, size_t));

void mp_get_memory_functions (void *(**) (size_t),
                  void *(**) (void *, size_t, size_t),
                  void (**) (void *, size_t));

#ifndef MINI_GMP_LIMB_TYPE
#define MINI_GMP_LIMB_TYPE long
#endif

typedef unsigned MINI_GMP_LIMB_TYPE mp_limb_t;
typedef long mp_size_t;
typedef unsigned long mp_bitcnt_t;

typedef mp_limb_t *mp_ptr;
typedef const mp_limb_t *mp_srcptr;

typedef struct
{
  int _mp_alloc;        /* Number of *limbs* allocated and pointed
                   to by the _mp_d field.  */
  int _mp_size;            /* abs(_mp_size) is the number of limbs the
                   last field points to.  If _mp_size is
                   negative this is a negative number.  */
  mp_limb_t *_mp_d;        /* Pointer to the limbs.  */
} __mpz_struct;

typedef __mpz_struct mpz_t[1];

typedef __mpz_struct *mpz_ptr;
typedef const __mpz_struct *mpz_srcptr;

extern const int mp_bits_per_limb;

void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
void mpn_zero (mp_ptr, mp_size_t);

int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
int mpn_zero_p (mp_srcptr, mp_size_t);

mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);

mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);

mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);

mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
int mpn_perfect_square_p (mp_srcptr, mp_size_t);
mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);

mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);

mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);

void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);

mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);

mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)

size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);

void mpz_init (mpz_t);
void mpz_init2 (mpz_t, mp_bitcnt_t);
void mpz_clear (mpz_t);

#define mpz_odd_p(z)   (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
#define mpz_even_p(z)  (! mpz_odd_p (z))

int mpz_sgn (const mpz_t);
int mpz_cmp_si (const mpz_t, long);
int mpz_cmp_ui (const mpz_t, unsigned long);
int mpz_cmp (const mpz_t, const mpz_t);
int mpz_cmpabs_ui (const mpz_t, unsigned long);
int mpz_cmpabs (const mpz_t, const mpz_t);
int mpz_cmp_d (const mpz_t, double);
int mpz_cmpabs_d (const mpz_t, double);

void mpz_abs (mpz_t, const mpz_t);
void mpz_neg (mpz_t, const mpz_t);
void mpz_swap (mpz_t, mpz_t);

void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
void mpz_add (mpz_t, const mpz_t, const mpz_t);
void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
void mpz_sub (mpz_t, const mpz_t, const mpz_t);

void mpz_mul_si (mpz_t, const mpz_t, long int);
void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_mul (mpz_t, const mpz_t, const mpz_t);
void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_addmul (mpz_t, const mpz_t, const mpz_t);
void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_submul (mpz_t, const mpz_t, const mpz_t);

void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);

void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);

void mpz_mod (mpz_t, const mpz_t, const mpz_t);

void mpz_divexact (mpz_t, const mpz_t, const mpz_t);

int mpz_divisible_p (const mpz_t, const mpz_t);
int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t);

unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);

unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);

void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);

int mpz_divisible_ui_p (const mpz_t, unsigned long);

unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
int mpz_invert (mpz_t, const mpz_t, const mpz_t);

void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
void mpz_sqrt (mpz_t, const mpz_t);
int mpz_perfect_square_p (const mpz_t);

void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);

void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
int mpz_root (mpz_t, const mpz_t, unsigned long);

void mpz_fac_ui (mpz_t, unsigned long);
void mpz_2fac_ui (mpz_t, unsigned long);
void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long);
void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);

int mpz_probab_prime_p (const mpz_t, int);

int mpz_tstbit (const mpz_t, mp_bitcnt_t);
void mpz_setbit (mpz_t, mp_bitcnt_t);
void mpz_clrbit (mpz_t, mp_bitcnt_t);
void mpz_combit (mpz_t, mp_bitcnt_t);

void mpz_com (mpz_t, const mpz_t);
void mpz_and (mpz_t, const mpz_t, const mpz_t);
void mpz_ior (mpz_t, const mpz_t, const mpz_t);
void mpz_xor (mpz_t, const mpz_t, const mpz_t);

mp_bitcnt_t mpz_popcount (const mpz_t);
mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);

int mpz_fits_slong_p (const mpz_t);
int mpz_fits_ulong_p (const mpz_t);
int mpz_fits_sint_p (const mpz_t);
int mpz_fits_uint_p (const mpz_t);
int mpz_fits_sshort_p (const mpz_t);
int mpz_fits_ushort_p (const mpz_t);
long int mpz_get_si (const mpz_t);
unsigned long int mpz_get_ui (const mpz_t);
double mpz_get_d (const mpz_t);
size_t mpz_size (const mpz_t);
mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);

void mpz_realloc2 (mpz_t, mp_bitcnt_t);
mp_srcptr mpz_limbs_read (mpz_srcptr);
mp_ptr mpz_limbs_modify (mpz_t, mp_size_t);
mp_ptr mpz_limbs_write (mpz_t, mp_size_t);
void mpz_limbs_finish (mpz_t, mp_size_t);
mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t);

#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}

void mpz_set_si (mpz_t, signed long int);
void mpz_set_ui (mpz_t, unsigned long int);
void mpz_set (mpz_t, const mpz_t);
void mpz_set_d (mpz_t, double);

void mpz_init_set_si (mpz_t, signed long int);
void mpz_init_set_ui (mpz_t, unsigned long int);
void mpz_init_set (mpz_t, const mpz_t);
void mpz_init_set_d (mpz_t, double);

size_t mpz_sizeinbase (const mpz_t, int);
char *mpz_get_str (char *, int, const mpz_t);
int mpz_set_str (mpz_t, const char *, int);
int mpz_init_set_str (mpz_t, const char *, int);

/* This long list taken from gmp.h. */
/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
   <iostream> defines EOF but not FILE.  */
#if defined (FILE)                                              \
  || defined (H_STDIO)                                          \
  || defined (_H_STDIO)               /* AIX */                 \
  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
  || defined (_STDIO_H_)              /* BSD, OSF */            \
  || defined (__STDIO_H)              /* Borland */             \
  || defined (__STDIO_H__)            /* IRIX */                \
  || defined (_STDIO_INCLUDED)        /* HPUX */                \
  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
  || defined (_FILE_DEFINED)          /* Microsoft */           \
  || defined (__STDIO__)              /* Apple MPW MrC */       \
  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
  || defined (_STDIO_H_INCLUDED)      /* QNX4 */        \
  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */        \
  || defined (__STDIO_LOADED)         /* VMS */            \
  || defined (_STDIO)                 /* HPE NonStop */         \
  || defined (__DEFINED_FILE)         /* musl */
size_t mpz_out_str (FILE *, int, const mpz_t);
#endif

void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);

#if defined (__cplusplus)
}
#endif
#endif /* __MINI_GMP_H__ */

#if !defined(MINI_GMP_DONT_USE_FLOAT_H)
#include <float.h>
#endif


/* Macros */
#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)

#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0)
#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))

#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)

#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))

#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))

#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))

#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b)))

#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
#define GMP_DBL_MANT_BITS DBL_MANT_DIG
#else
#define GMP_DBL_MANT_BITS (53)
#endif

/* Return non-zero if xp,xsize and yp,ysize overlap.
   If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
   overlap.  If both these are false, there's an overlap. */
#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize)                \
  ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))

#define gmp_assert_nocarry(x) do { \
    mp_limb_t __cy = (x);       \
    assert (__cy == 0);           \
    (void) (__cy);           \
  } while (0)

#define gmp_clz(count, x) do {                        \
    mp_limb_t __clz_x = (x);                        \
    unsigned __clz_c = 0;                        \
    int LOCAL_SHIFT_BITS = 8;                        \
    if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)                \
      for (;                                \
       (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0;    \
       __clz_c += 8)                        \
    { __clz_x <<= LOCAL_SHIFT_BITS;    }                \
    for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++)        \
      __clz_x <<= 1;                            \
    (count) = __clz_c;                            \
  } while (0)

#define gmp_ctz(count, x) do {                        \
    mp_limb_t __ctz_x = (x);                        \
    unsigned __ctz_c = 0;                        \
    gmp_clz (__ctz_c, __ctz_x & - __ctz_x);                \
    (count) = GMP_LIMB_BITS - 1 - __ctz_c;                \
  } while (0)

#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
  do {                                    \
    mp_limb_t __x;                            \
    __x = (al) + (bl);                            \
    (sh) = (ah) + (bh) + (__x < (al));                    \
    (sl) = __x;                                \
  } while (0)

#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
  do {                                    \
    mp_limb_t __x;                            \
    __x = (al) - (bl);                            \
    (sh) = (ah) - (bh) - ((al) < (bl));                    \
    (sl) = __x;                                \
  } while (0)

#define gmp_umul_ppmm(w1, w0, u, v)                    \
  do {                                    \
    int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;                \
    if (sizeof(unsigned int) * CHAR_BIT >= 2 * GMP_LIMB_BITS)        \
      {                                    \
    unsigned int __ww = (unsigned int) (u) * (v);            \
    w0 = (mp_limb_t) __ww;                        \
    w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS);            \
      }                                    \
    else if (GMP_ULONG_BITS >= 2 * GMP_LIMB_BITS)            \
      {                                    \
    unsigned long int __ww = (unsigned long int) (u) * (v);        \
    w0 = (mp_limb_t) __ww;                        \
    w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS);            \
      }                                    \
    else {                                \
      mp_limb_t __x0, __x1, __x2, __x3;                    \
      unsigned __ul, __vl, __uh, __vh;                    \
      mp_limb_t __u = (u), __v = (v);                    \
      assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));        \
                                    \
      __ul = __u & GMP_LLIMB_MASK;                    \
      __uh = __u >> (GMP_LIMB_BITS / 2);                \
      __vl = __v & GMP_LLIMB_MASK;                    \
      __vh = __v >> (GMP_LIMB_BITS / 2);                \
                                    \
      __x0 = (mp_limb_t) __ul * __vl;                    \
      __x1 = (mp_limb_t) __ul * __vh;                    \
      __x2 = (mp_limb_t) __uh * __vl;                    \
      __x3 = (mp_limb_t) __uh * __vh;                    \
                                    \
      __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */    \
      __x1 += __x2;        /* but this indeed can */        \
      if (__x1 < __x2)        /* did we get it? */            \
    __x3 += GMP_HLIMB_BIT;    /* yes, add it in the proper pos. */    \
                                    \
      (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2));            \
      (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK);    \
    }                                    \
  } while (0)

/* If mp_limb_t is of size smaller than int, plain u*v implies
   automatic promotion to *signed* int, and then multiply may overflow
   and cause undefined behavior. Explicitly cast to unsigned int for
   that case. */
#define gmp_umullo_limb(u, v) \
  ((sizeof(mp_limb_t) >= sizeof(int)) ? (u)*(v) : (unsigned int)(u) * (v))

#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di)            \
  do {                                    \
    mp_limb_t _qh, _ql, _r, _mask;                    \
    gmp_umul_ppmm (_qh, _ql, (nh), (di));                \
    gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));        \
    _r = (nl) - gmp_umullo_limb (_qh, (d));                \
    _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */        \
    _qh += _mask;                            \
    _r += _mask & (d);                            \
    if (_r >= (d))                            \
      {                                    \
    _r -= (d);                            \
    _qh++;                                \
      }                                    \
                                    \
    (r) = _r;                                \
    (q) = _qh;                                \
  } while (0)

#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv)        \
  do {                                    \
    mp_limb_t _q0, _t1, _t0, _mask;                    \
    gmp_umul_ppmm ((q), _q0, (n2), (dinv));                \
    gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1));            \
                                    \
    /* Compute the two most significant limbs of n - q'd */        \
    (r1) = (n1) - gmp_umullo_limb ((d1), (q));                \
    gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0));        \
    gmp_umul_ppmm (_t1, _t0, (d0), (q));                \
    gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0);            \
    (q)++;                                \
                                    \
    /* Conditionally adjust q and the remainders */            \
    _mask = - (mp_limb_t) ((r1) >= _q0);                \
    (q) += _mask;                            \
    gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
    if ((r1) >= (d1))                            \
      {                                    \
    if ((r1) > (d1) || (r0) >= (d0))                \
      {                                \
        (q)++;                            \
        gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0));    \
      }                                \
      }                                    \
  } while (0)

/* Swap macros. */
#define MP_LIMB_T_SWAP(x, y)                        \
  do {                                    \
    mp_limb_t __mp_limb_t_swap__tmp = (x);                \
    (x) = (y);                                \
    (y) = __mp_limb_t_swap__tmp;                    \
  } while (0)
#define MP_SIZE_T_SWAP(x, y)                        \
  do {                                    \
    mp_size_t __mp_size_t_swap__tmp = (x);                \
    (x) = (y);                                \
    (y) = __mp_size_t_swap__tmp;                    \
  } while (0)
#define MP_BITCNT_T_SWAP(x,y)            \
  do {                        \
    mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x);    \
    (x) = (y);                    \
    (y) = __mp_bitcnt_t_swap__tmp;        \
  } while (0)
#define MP_PTR_SWAP(x, y)                        \
  do {                                    \
    mp_ptr __mp_ptr_swap__tmp = (x);                    \
    (x) = (y);                                \
    (y) = __mp_ptr_swap__tmp;                        \
  } while (0)
#define MP_SRCPTR_SWAP(x, y)                        \
  do {                                    \
    mp_srcptr __mp_srcptr_swap__tmp = (x);                \
    (x) = (y);                                \
    (y) = __mp_srcptr_swap__tmp;                    \
  } while (0)

#define MPN_PTR_SWAP(xp,xs, yp,ys)                    \
  do {                                    \
    MP_PTR_SWAP (xp, yp);                        \
    MP_SIZE_T_SWAP (xs, ys);                        \
  } while(0)
#define MPN_SRCPTR_SWAP(xp,xs, yp,ys)                    \
  do {                                    \
    MP_SRCPTR_SWAP (xp, yp);                        \
    MP_SIZE_T_SWAP (xs, ys);                        \
  } while(0)

#define MPZ_PTR_SWAP(x, y)                        \
  do {                                    \
    mpz_ptr __mpz_ptr_swap__tmp = (x);                    \
    (x) = (y);                                \
    (y) = __mpz_ptr_swap__tmp;                        \
  } while (0)
#define MPZ_SRCPTR_SWAP(x, y)                        \
  do {                                    \
    mpz_srcptr __mpz_srcptr_swap__tmp = (x);                \
    (x) = (y);                                \
    (y) = __mpz_srcptr_swap__tmp;                    \
  } while (0)

const int mp_bits_per_limb = GMP_LIMB_BITS;


/* Memory allocation and other helper functions. */
static void
gmp_die (const char *msg)
{
  fprintf (stderr, "%s\n", msg);
  abort();
}

static void *
gmp_default_alloc (size_t size)
{
  void *p;

  assert (size > 0);

  p = malloc (size);
  if (!p)
    gmp_die("gmp_default_alloc: Virtual memory exhausted.");

  return p;
}

static void *
gmp_default_realloc (void *old, size_t unused_old_size, size_t new_size)
{
  void * p;

  p = realloc (old, new_size);

  if (!p)
    gmp_die("gmp_default_realloc: Virtual memory exhausted.");

  return p;
}

static void
gmp_default_free (void *p, size_t unused_size)
{
  free (p);
}

static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
static void (*gmp_free_func) (void *, size_t) = gmp_default_free;

void
mp_get_memory_functions (void *(**alloc_func) (size_t),
             void *(**realloc_func) (void *, size_t, size_t),
             void (**free_func) (void *, size_t))
{
  if (alloc_func)
    *alloc_func = gmp_allocate_func;

  if (realloc_func)
    *realloc_func = gmp_reallocate_func;

  if (free_func)
    *free_func = gmp_free_func;
}

void
mp_set_memory_functions (void *(*alloc_func) (size_t),
             void *(*realloc_func) (void *, size_t, size_t),
             void (*free_func) (void *, size_t))
{
  if (!alloc_func)
    alloc_func = gmp_default_alloc;
  if (!realloc_func)
    realloc_func = gmp_default_realloc;
  if (!free_func)
    free_func = gmp_default_free;

  gmp_allocate_func = alloc_func;
  gmp_reallocate_func = realloc_func;
  gmp_free_func = free_func;
}

#define gmp_alloc(size) ((*gmp_allocate_func)((size)))
#define gmp_free(p, size) ((*gmp_free_func) ((p), (size)))
#define gmp_realloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size))

static mp_ptr
gmp_alloc_limbs (mp_size_t size)
{
  return (mp_ptr) gmp_alloc (size * sizeof (mp_limb_t));
}

static mp_ptr
gmp_realloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size)
{
  assert (size > 0);
  return (mp_ptr) gmp_realloc (old, old_size * sizeof (mp_limb_t), size * sizeof (mp_limb_t));
}

static void
gmp_free_limbs (mp_ptr old, mp_size_t size)
{
  gmp_free (old, size * sizeof (mp_limb_t));
}


/* MPN interface */

void
mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
{
  mp_size_t i;
  for (i = 0; i < n; i++)
    d[i] = s[i];
}

void
mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
{
  while (--n >= 0)
    d[n] = s[n];
}

int
mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
  while (--n >= 0)
    {
      if (ap[n] != bp[n])
    return ap[n] > bp[n] ? 1 : -1;
    }
  return 0;
}

static int
mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
  if (an != bn)
    return an < bn ? -1 : 1;
  else
    return mpn_cmp (ap, bp, an);
}

static mp_size_t
mpn_normalized_size (mp_srcptr xp, mp_size_t n)
{
  while (n > 0 && xp[n-1] == 0)
    --n;
  return n;
}

int
mpn_zero_p(mp_srcptr rp, mp_size_t n)
{
  return mpn_normalized_size (rp, n) == 0;
}

void
mpn_zero (mp_ptr rp, mp_size_t n)
{
  while (--n >= 0)
    rp[n] = 0;
}

mp_limb_t
mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
{
  mp_size_t i;

  assert (n > 0);
  i = 0;
  do
    {
      mp_limb_t r = ap[i] + b;
      /* Carry out */
      b = (r < b);
      rp[i] = r;
    }
  while (++i < n);

  return b;
}

mp_limb_t
mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
  mp_size_t i;
  mp_limb_t cy;

  for (i = 0, cy = 0; i < n; i++)
    {
      mp_limb_t a, b, r;
      a = ap[i]; b = bp[i];
      r = a + cy;
      cy = (r < cy);
      r += b;
      cy += (r < b);
      rp[i] = r;
    }
  return cy;
}

mp_limb_t
mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
  mp_limb_t cy;

  assert (an >= bn);

  cy = mpn_add_n (rp, ap, bp, bn);
  if (an > bn)
    cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
  return cy;
}

mp_limb_t
mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
{
  mp_size_t i;

  assert (n > 0);

  i = 0;
  do
    {
      mp_limb_t a = ap[i];
      /* Carry out */
      mp_limb_t cy = a < b;
      rp[i] = a - b;
      b = cy;
    }
  while (++i < n);

  return b;
}

mp_limb_t
mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
  mp_size_t i;
  mp_limb_t cy;

  for (i = 0, cy = 0; i < n; i++)
    {
      mp_limb_t a, b;
      a = ap[i]; b = bp[i];
      b += cy;
      cy = (b < cy);
      cy += (a < b);
      rp[i] = a - b;
    }
  return cy;
}

mp_limb_t
mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
  mp_limb_t cy;

  assert (an >= bn);

  cy = mpn_sub_n (rp, ap, bp, bn);
  if (an > bn)
    cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
  return cy;
}

mp_limb_t
mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
  mp_limb_t ul, cl, hpl, lpl;

  assert (n >= 1);

  cl = 0;
  do
    {
      ul = *up++;
      gmp_umul_ppmm (hpl, lpl, ul, vl);

      lpl += cl;
      cl = (lpl < cl) + hpl;

      *rp++ = lpl;
    }
  while (--n != 0);

  return cl;
}

mp_limb_t
mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
  mp_limb_t ul, cl, hpl, lpl, rl;

  assert (n >= 1);

  cl = 0;
  do
    {
      ul = *up++;
      gmp_umul_ppmm (hpl, lpl, ul, vl);

      lpl += cl;
      cl = (lpl < cl) + hpl;

      rl = *rp;
      lpl = rl + lpl;
      cl += lpl < rl;
      *rp++ = lpl;
    }
  while (--n != 0);

  return cl;
}

mp_limb_t
mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
  mp_limb_t ul, cl, hpl, lpl, rl;

  assert (n >= 1);

  cl = 0;
  do
    {
      ul = *up++;
      gmp_umul_ppmm (hpl, lpl, ul, vl);

      lpl += cl;
      cl = (lpl < cl) + hpl;

      rl = *rp;
      lpl = rl - lpl;
      cl += lpl > rl;
      *rp++ = lpl;
    }
  while (--n != 0);

  return cl;
}

mp_limb_t
mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
{
  assert (un >= vn);
  assert (vn >= 1);
  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un));
  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn));

  /* We first multiply by the low order limb. This result can be
     stored, not added, to rp. We also avoid a loop for zeroing this
     way. */

  rp[un] = mpn_mul_1 (rp, up, un, vp[0]);

  /* Now accumulate the product of up[] and the next higher limb from
     vp[]. */

  while (--vn >= 1)
    {
      rp += 1, vp += 1;
      rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
    }
  return rp[un];
}

void
mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
  mpn_mul (rp, ap, n, bp, n);
}

void
mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
{
  mpn_mul (rp, ap, n, ap, n);
}

mp_limb_t
mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
{
  mp_limb_t high_limb, low_limb;
  unsigned int tnc;
  mp_limb_t retval;

  assert (n >= 1);
  assert (cnt >= 1);
  assert (cnt < GMP_LIMB_BITS);

  up += n;
  rp += n;

  tnc = GMP_LIMB_BITS - cnt;
  low_limb = *--up;
  retval = low_limb >> tnc;
  high_limb = (low_limb << cnt);

  while (--n != 0)
    {
      low_limb = *--up;
      *--rp = high_limb | (low_limb >> tnc);
      high_limb = (low_limb << cnt);
    }
  *--rp = high_limb;

  return retval;
}

mp_limb_t
mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
{
  mp_limb_t high_limb, low_limb;
  unsigned int tnc;
  mp_limb_t retval;

  assert (n >= 1);
  assert (cnt >= 1);
  assert (cnt < GMP_LIMB_BITS);

  tnc = GMP_LIMB_BITS - cnt;
  high_limb = *up++;
  retval = (high_limb << tnc);
  low_limb = high_limb >> cnt;

  while (--n != 0)
    {
      high_limb = *up++;
      *rp++ = low_limb | (high_limb << tnc);
      low_limb = high_limb >> cnt;
    }
  *rp = low_limb;

  return retval;
}

static mp_bitcnt_t
mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un,
         mp_limb_t ux)
{
  unsigned cnt;

  assert (ux == 0 || ux == GMP_LIMB_MAX);
  assert (0 <= i && i <= un );

  while (limb == 0)
    {
      i++;
      if (i == un)
    return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
      limb = ux ^ up[i];
    }
  gmp_ctz (cnt, limb);
  return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
}

mp_bitcnt_t
mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit)
{
  mp_size_t i;
  i = bit / GMP_LIMB_BITS;

  return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
              i, ptr, i, 0);
}

mp_bitcnt_t
mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
{
  mp_size_t i;
  i = bit / GMP_LIMB_BITS;

  return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
              i, ptr, i, GMP_LIMB_MAX);
}

void
mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
{
  while (--n >= 0)
    *rp++ = ~ *up++;
}

mp_limb_t
mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n)
{
  while (*up == 0)
    {
      *rp = 0;
      if (!--n)
    return 0;
      ++up; ++rp;
    }
  *rp = - *up;
  mpn_com (++rp, ++up, --n);
  return 1;
}


/* MPN division interface. */

/* The 3/2 inverse is defined as

     m = floor( (B^3-1) / (B u1 + u0)) - B
*/
mp_limb_t
mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
{
  mp_limb_t r, m;

  {
    mp_limb_t p, ql;
    unsigned ul, uh, qh;

    assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));
    /* For notation, let b denote the half-limb base, so that B = b^2.
       Split u1 = b uh + ul. */
    ul = u1 & GMP_LLIMB_MASK;
    uh = u1 >> (GMP_LIMB_BITS / 2);

    /* Approximation of the high half of quotient. Differs from the 2/1
       inverse of the half limb uh, since we have already subtracted
       u0. */
    qh = (u1 ^ GMP_LIMB_MAX) / uh;

    /* Adjust to get a half-limb 3/2 inverse, i.e., we want

       qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
       = floor( (b (~u) + b-1) / u),

       and the remainder

       r = b (~u) + b-1 - qh (b uh + ul)
       = b (~u - qh uh) + b-1 - qh ul

       Subtraction of qh ul may underflow, which implies adjustments.
       But by normalization, 2 u >= B > qh ul, so we need to adjust by
       at most 2.
    */

    r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;

    p = (mp_limb_t) qh * ul;
    /* Adjustment steps taken from udiv_qrnnd_c */
    if (r < p)
      {
    qh--;
    r += u1;
    if (r >= u1) /* i.e. we didn't get carry when adding to r */
      if (r < p)
        {
          qh--;
          r += u1;
        }
      }
    r -= p;

    /* Low half of the quotient is

       ql = floor ( (b r + b-1) / u1).

       This is a 3/2 division (on half-limbs), for which qh is a
       suitable inverse. */

    p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
    /* Unlike full-limb 3/2, we can add 1 without overflow. For this to
       work, it is essential that ql is a full mp_limb_t. */
    ql = (p >> (GMP_LIMB_BITS / 2)) + 1;

    /* By the 3/2 trick, we don't need the high half limb. */
    r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;

    if (r >= (GMP_LIMB_MAX & (p << (GMP_LIMB_BITS / 2))))
      {
    ql--;
    r += u1;
      }
    m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
    if (r >= u1)
      {
    m++;
    r -= u1;
      }
  }

  /* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a
     3/2 inverse. */
  if (u0 > 0)
    {
      mp_limb_t th, tl;
      r = ~r;
      r += u0;
      if (r < u0)
    {
      m--;
      if (r >= u1)
        {
          m--;
          r -= u1;
        }
      r -= u1;
    }
      gmp_umul_ppmm (th, tl, u0, m);
      r += th;
      if (r < th)
    {
      m--;
      m -= ((r > u1) | ((r == u1) & (tl > u0)));
    }
    }

  return m;
}

struct gmp_div_inverse
{
  /* Normalization shift count. */
  unsigned shift;
  /* Normalized divisor (d0 unused for mpn_div_qr_1) */
  mp_limb_t d1, d0;
  /* Inverse, for 2/1 or 3/2. */
  mp_limb_t di;
};

static void
mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
{
  unsigned shift;

  assert (d > 0);
  gmp_clz (shift, d);
  inv->shift = shift;
  inv->d1 = d << shift;
  inv->di = mpn_invert_limb (inv->d1);
}

static void
mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
             mp_limb_t d1, mp_limb_t d0)
{
  unsigned shift;

  assert (d1 > 0);
  gmp_clz (shift, d1);
  inv->shift = shift;
  if (shift > 0)
    {
      d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
      d0 <<= shift;
    }
  inv->d1 = d1;
  inv->d0 = d0;
  inv->di = mpn_invert_3by2 (d1, d0);
}

static void
mpn_div_qr_invert (struct gmp_div_inverse *inv,
           mp_srcptr dp, mp_size_t dn)
{
  assert (dn > 0);

  if (dn == 1)
    mpn_div_qr_1_invert (inv, dp[0]);
  else if (dn == 2)
    mpn_div_qr_2_invert (inv, dp[1], dp[0]);
  else
    {
      unsigned shift;
      mp_limb_t d1, d0;

      d1 = dp[dn-1];
      d0 = dp[dn-2];
      assert (d1 > 0);
      gmp_clz (shift, d1);
      inv->shift = shift;
      if (shift > 0)
    {
      d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
      d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
    }
      inv->d1 = d1;
      inv->d0 = d0;
      inv->di = mpn_invert_3by2 (d1, d0);
    }
}

/* Not matching current public gmp interface, rather corresponding to
   the sbpi1_div_* functions. */
static mp_limb_t
mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
             const struct gmp_div_inverse *inv)
{
  mp_limb_t d, di;
  mp_limb_t r;
  mp_ptr tp = NULL;
  mp_size_t tn = 0;

  if (inv->shift > 0)
    {
      /* Shift, reusing qp area if possible. In-place shift if qp == np. */
      tp = qp;
      if (!tp)
        {
       tn = nn;
       tp = gmp_alloc_limbs (tn);
        }
      r = mpn_lshift (tp, np, nn, inv->shift);
      np = tp;
    }
  else
    r = 0;

  d = inv->d1;
  di = inv->di;
  while (--nn >= 0)
    {
      mp_limb_t q;

      gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
      if (qp)
    qp[nn] = q;
    }
  if (tn)
    gmp_free_limbs (tp, tn);

  return r >> inv->shift;
}

static void
mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
             const struct gmp_div_inverse *inv)
{
  unsigned shift;
  mp_size_t i;
  mp_limb_t d1, d0, di, r1, r0;

  assert (nn >= 2);
  shift = inv->shift;
  d1 = inv->d1;
  d0 = inv->d0;
  di = inv->di;

  if (shift > 0)
    r1 = mpn_lshift (np, np, nn, shift);
  else
    r1 = 0;

  r0 = np[nn - 1];

  i = nn - 2;
  do
    {
      mp_limb_t n0, q;
      n0 = np[i];
      gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);

      if (qp)
    qp[i] = q;
    }
  while (--i >= 0);

  if (shift > 0)
    {
      assert ((r0 & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - shift))) == 0);
      r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
      r1 >>= shift;
    }

  np[1] = r1;
  np[0] = r0;
}

static void
mpn_div_qr_pi1 (mp_ptr qp,
        mp_ptr np, mp_size_t nn, mp_limb_t n1,
        mp_srcptr dp, mp_size_t dn,
        mp_limb_t dinv)
{
  mp_size_t i;

  mp_limb_t d1, d0;
  mp_limb_t cy, cy1;
  mp_limb_t q;

  assert (dn > 2);
  assert (nn >= dn);

  d1 = dp[dn - 1];
  d0 = dp[dn - 2];

  assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
  /* Iteration variable is the index of the q limb.
   *
   * We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
   * by            <d1,          d0,        dp[dn-3],  ..., dp[0] >
   */

  i = nn - dn;
  do
    {
      mp_limb_t n0 = np[dn-1+i];

      if (n1 == d1 && n0 == d0)
    {
      q = GMP_LIMB_MAX;
      mpn_submul_1 (np+i, dp, dn, q);
      n1 = np[dn-1+i];    /* update n1, last loop's value will now be invalid */
    }
      else
    {
      gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);

      cy = mpn_submul_1 (np + i, dp, dn-2, q);

      cy1 = n0 < cy;
      n0 = n0 - cy;
      cy = n1 < cy1;
      n1 = n1 - cy1;
      np[dn-2+i] = n0;

      if (cy != 0)
        {
          n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
          q--;
        }
    }

      if (qp)
    qp[i] = q;
    }
  while (--i >= 0);

  np[dn - 1] = n1;
}

static void
mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
           mp_srcptr dp, mp_size_t dn,
           const struct gmp_div_inverse *inv)
{
  assert (dn > 0);
  assert (nn >= dn);

  if (dn == 1)
    np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
  else if (dn == 2)
    mpn_div_qr_2_preinv (qp, np, nn, inv);
  else
    {
      mp_limb_t nh;
      unsigned shift;

      assert (inv->d1 == dp[dn-1]);
      assert (inv->d0 == dp[dn-2]);
      assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);

      shift = inv->shift;
      if (shift > 0)
    nh = mpn_lshift (np, np, nn, shift);
      else
    nh = 0;

      mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);

      if (shift > 0)
    gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
    }
}

static void
mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
{
  struct gmp_div_inverse inv;
  mp_ptr tp = NULL;

  assert (dn > 0);
  assert (nn >= dn);

  mpn_div_qr_invert (&inv, dp, dn);
  if (dn > 2 && inv.shift > 0)
    {
      tp = gmp_alloc_limbs (dn);
      gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
      dp = tp;
    }
  mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
  if (tp)
    gmp_free_limbs (tp, dn);
}


/* MPN base conversion. */
static unsigned
mpn_base_power_of_two_p (unsigned b)
{
  switch (b)
    {
    case 2: return 1;
    case 4: return 2;
    case 8: return 3;
    case 16: return 4;
    case 32: return 5;
    case 64: return 6;
    case 128: return 7;
    case 256: return 8;
    default: return 0;
    }
}

struct mpn_base_info
{
  /* bb is the largest power of the base which fits in one limb, and
     exp is the corresponding exponent. */
  unsigned exp;
  mp_limb_t bb;
};

static void
mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
{
  mp_limb_t m;
  mp_limb_t p;
  unsigned exp;

  m = GMP_LIMB_MAX / b;
  for (exp = 1, p = b; p <= m; exp++)
    p *= b;

  info->exp = exp;
  info->bb = p;
}

static mp_bitcnt_t
mpn_limb_size_in_base_2 (mp_limb_t u)
{
  unsigned shift;

  assert (u > 0);
  gmp_clz (shift, u);
  return GMP_LIMB_BITS - shift;
}

static size_t
mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
{
  unsigned char mask;
  size_t sn, j;
  mp_size_t i;
  unsigned shift;

  sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
    + bits - 1) / bits;

  mask = (1U << bits) - 1;

  for (i = 0, j = sn, shift = 0; j-- > 0;)
    {
      unsigned char digit = up[i] >> shift;

      shift += bits;

      if (shift >= GMP_LIMB_BITS && ++i < un)
    {
      shift -= GMP_LIMB_BITS;
      digit |= up[i] << (bits - shift);
    }
      sp[j] = digit & mask;
    }
  return sn;
}

/* We generate digits from the least significant end, and reverse at
   the end. */
static size_t
mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
          const struct gmp_div_inverse *binv)
{
  mp_size_t i;
  for (i = 0; w > 0; i++)
    {
      mp_limb_t h, l, r;

      h = w >> (GMP_LIMB_BITS - binv->shift);
      l = w << binv->shift;

      gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
      assert ((r & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - binv->shift))) == 0);
      r >>= binv->shift;

      sp[i] = r;
    }
  return i;
}

static size_t
mpn_get_str_other (unsigned char *sp,
           int base, const struct mpn_base_info *info,
           mp_ptr up, mp_size_t un)
{
  struct gmp_div_inverse binv;
  size_t sn;
  size_t i;

  mpn_div_qr_1_invert (&binv, base);

  sn = 0;

  if (un > 1)
    {
      struct gmp_div_inverse bbinv;
      mpn_div_qr_1_invert (&bbinv, info->bb);

      do
    {
      mp_limb_t w;
      size_t done;
      w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
      un -= (up[un-1] == 0);
      done = mpn_limb_get_str (sp + sn, w, &binv);

      for (sn += done; done < info->exp; done++)
        sp[sn++] = 0;
    }
      while (un > 1);
    }
  sn += mpn_limb_get_str (sp + sn, up[0], &binv);

  /* Reverse order */
  for (i = 0; 2*i + 1 < sn; i++)
    {
      unsigned char t = sp[i];
      sp[i] = sp[sn - i - 1];
      sp[sn - i - 1] = t;
    }

  return sn;
}

size_t
mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
{
  unsigned bits;

  assert (un > 0);
  assert (up[un-1] > 0);

  bits = mpn_base_power_of_two_p (base);
  if (bits)
    return mpn_get_str_bits (sp, bits, up, un);
  else
    {
      struct mpn_base_info info;

      mpn_get_base_info (&info, base);
      return mpn_get_str_other (sp, base, &info, up, un);
    }
}

static mp_size_t
mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
          unsigned bits)
{
  mp_size_t rn;
  mp_limb_t limb;
  unsigned shift;

  for (limb = 0, rn = 0, shift = 0; sn-- > 0; )
    {
      limb |= (mp_limb_t) sp[sn] << shift;
      shift += bits;
      if (shift >= GMP_LIMB_BITS)
    {
      shift -= GMP_LIMB_BITS;
      rp[rn++] = limb;
      /* Next line is correct also if shift == 0,
         bits == 8, and mp_limb_t == unsigned char. */
      limb = (unsigned int) sp[sn] >> (bits - shift);
    }
    }
  if (limb != 0)
    rp[rn++] = limb;
  else
    rn = mpn_normalized_size (rp, rn);
  return rn;
}

/* Result is usually normalized, except for all-zero input, in which
   case a single zero limb is written at *RP, and 1 is returned. */
static mp_size_t
mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
           mp_limb_t b, const struct mpn_base_info *info)
{
  mp_size_t rn;
  mp_limb_t w;
  unsigned k;
  size_t j;

  assert (sn > 0);

  k = 1 + (sn - 1) % info->exp;

  j = 0;
  w = sp[j++];
  while (--k != 0)
    w = w * b + sp[j++];

  rp[0] = w;

  for (rn = 1; j < sn;)
    {
      mp_limb_t cy;

      w = sp[j++];
      for (k = 1; k < info->exp; k++)
    w = w * b + sp[j++];

      cy = mpn_mul_1 (rp, rp, rn, info->bb);
      cy += mpn_add_1 (rp, rp, rn, w);
      if (cy > 0)
    rp[rn++] = cy;
    }
  assert (j == sn);

  return rn;
}

mp_size_t
mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
{
  unsigned bits;

  if (sn == 0)
    return 0;

  bits = mpn_base_power_of_two_p (base);
  if (bits)
    return mpn_set_str_bits (rp, sp, sn, bits);
  else
    {
      struct mpn_base_info info;

      mpn_get_base_info (&info, base);
      return mpn_set_str_other (rp, sp, sn, base, &info);
    }
}


/* MPZ interface */
void
mpz_init (mpz_t r)
{
  static const mp_limb_t dummy_limb = GMP_LIMB_MAX & 0xc1a0;

  r->_mp_alloc = 0;
  r->_mp_size = 0;
  r->_mp_d = (mp_ptr) &dummy_limb;
}

/* The utility of this function is a bit limited, since many functions
   assigns the result variable using mpz_swap. */
void
mpz_init2 (mpz_t r, mp_bitcnt_t bits)
{
  mp_size_t rn;

  bits -= (bits != 0);        /* Round down, except if 0 */
  rn = 1 + bits / GMP_LIMB_BITS;

  r->_mp_alloc = rn;
  r->_mp_size = 0;
  r->_mp_d = gmp_alloc_limbs (rn);
}

void
mpz_clear (mpz_t r)
{
  if (r->_mp_alloc)
    gmp_free_limbs (r->_mp_d, r->_mp_alloc);
}

static mp_ptr
mpz_realloc (mpz_t r, mp_size_t size)
{
  size = GMP_MAX (size, 1);

  if (r->_mp_alloc)
    r->_mp_d = gmp_realloc_limbs (r->_mp_d, r->_mp_alloc, size);
  else
    r->_mp_d = gmp_alloc_limbs (size);
  r->_mp_alloc = size;

  if (GMP_ABS (r->_mp_size) > size)
    r->_mp_size = 0;

  return r->_mp_d;
}

/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs.  */
#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc            \
              ? mpz_realloc(z,n)            \
              : (z)->_mp_d)

/* MPZ assignment and basic conversions. */
void
mpz_set_si (mpz_t r, signed long int x)
{
  if (x >= 0)
    mpz_set_ui (r, x);
  else /* (x < 0) */
    if (GMP_LIMB_BITS < GMP_ULONG_BITS)
      {
    mpz_set_ui (r, GMP_NEG_CAST (unsigned long int, x));
    mpz_neg (r, r);
      }
  else
    {
      r->_mp_size = -1;
      MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x);
    }
}

void
mpz_set_ui (mpz_t r, unsigned long int x)
{
  if (x > 0)
    {
      r->_mp_size = 1;
      MPZ_REALLOC (r, 1)[0] = x;
      if (GMP_LIMB_BITS < GMP_ULONG_BITS)
    {
      int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
      while (x >>= LOCAL_GMP_LIMB_BITS)
        {
          ++ r->_mp_size;
          MPZ_REALLOC (r, r->_mp_size)[r->_mp_size - 1] = x;
        }
    }
    }
  else
    r->_mp_size = 0;
}

void
mpz_set (mpz_t r, const mpz_t x)
{
  /* Allow the NOP r == x */
  if (r != x)
    {
      mp_size_t n;
      mp_ptr rp;

      n = GMP_ABS (x->_mp_size);
      rp = MPZ_REALLOC (r, n);

      mpn_copyi (rp, x->_mp_d, n);
      r->_mp_size = x->_mp_size;
    }
}

void
mpz_init_set_si (mpz_t r, signed long int x)
{
  mpz_init (r);
  mpz_set_si (r, x);
}

void
mpz_init_set_ui (mpz_t r, unsigned long int x)
{
  mpz_init (r);
  mpz_set_ui (r, x);
}

void
mpz_init_set (mpz_t r, const mpz_t x)
{
  mpz_init (r);
  mpz_set (r, x);
}

int
mpz_fits_slong_p (const mpz_t u)
{
  return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0;
}

static int
mpn_absfits_ulong_p (mp_srcptr up, mp_size_t un)
{
  int ulongsize = GMP_ULONG_BITS / GMP_LIMB_BITS;
  mp_limb_t ulongrem = 0;

  if (GMP_ULONG_BITS % GMP_LIMB_BITS != 0)
    ulongrem = (mp_limb_t) (ULONG_MAX >> GMP_LIMB_BITS * ulongsize) + 1;

  return un <= ulongsize || (up[ulongsize] < ulongrem && un == ulongsize + 1);
}

int
mpz_fits_ulong_p (const mpz_t u)
{
  mp_size_t us = u->_mp_size;

  return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us);
}

int
mpz_fits_sint_p (const mpz_t u)
{
  return mpz_cmp_si (u, INT_MAX) <= 0 && mpz_cmp_si (u, INT_MIN) >= 0;
}

int
mpz_fits_uint_p (const mpz_t u)
{
  return u->_mp_size >= 0 && mpz_cmpabs_ui (u, UINT_MAX) <= 0;
}

int
mpz_fits_sshort_p (const mpz_t u)
{
  return mpz_cmp_si (u, SHRT_MAX) <= 0 && mpz_cmp_si (u, SHRT_MIN) >= 0;
}

int
mpz_fits_ushort_p (const mpz_t u)
{
  return u->_mp_size >= 0 && mpz_cmpabs_ui (u, USHRT_MAX) <= 0;
}

long int
mpz_get_si (const mpz_t u)
{
  unsigned long r = mpz_get_ui (u);
  unsigned long c = -LONG_MAX - LONG_MIN;

  if (u->_mp_size < 0)
    /* This expression is necessary to properly handle -LONG_MIN */
    return -(long) c - (long) ((r - c) & LONG_MAX);
  else
    return (long) (r & LONG_MAX);
}

unsigned long int
mpz_get_ui (const mpz_t u)
{
  if (GMP_LIMB_BITS < GMP_ULONG_BITS)
    {
      int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
      unsigned long r = 0;
      mp_size_t n = GMP_ABS (u->_mp_size);
      n = GMP_MIN (n, 1 + (mp_size_t) (GMP_ULONG_BITS - 1) / GMP_LIMB_BITS);
      while (--n >= 0)
    r = (r << LOCAL_GMP_LIMB_BITS) + u->_mp_d[n];
      return r;
    }

  return u->_mp_size == 0 ? 0 : u->_mp_d[0];
}

size_t
mpz_size (const mpz_t u)
{
  return GMP_ABS (u->_mp_size);
}

mp_limb_t
mpz_getlimbn (const mpz_t u, mp_size_t n)
{
  if (n >= 0 && n < GMP_ABS (u->_mp_size))
    return u->_mp_d[n];
  else
    return 0;
}

void
mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
{
  mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS);
}

mp_srcptr
mpz_limbs_read (mpz_srcptr x)
{
  return x->_mp_d;
}

mp_ptr
mpz_limbs_modify (mpz_t x, mp_size_t n)
{
  assert (n > 0);
  return MPZ_REALLOC (x, n);
}

mp_ptr
mpz_limbs_write (mpz_t x, mp_size_t n)
{
  return mpz_limbs_modify (x, n);
}

void
mpz_limbs_finish (mpz_t x, mp_size_t xs)
{
  mp_size_t xn;
  xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs));
  x->_mp_size = xs < 0 ? -xn : xn;
}

static mpz_srcptr
mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
{
  x->_mp_alloc = 0;
  x->_mp_d = (mp_ptr) xp;
  x->_mp_size = xs;
  return x;
}

mpz_srcptr
mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
{
  mpz_roinit_normal_n (x, xp, xs);
  mpz_limbs_finish (x, xs);
  return x;
}


/* Conversions and comparison to double. */
void
mpz_set_d (mpz_t r, double x)
{
  int sign;
  mp_ptr rp;
  mp_size_t rn, i;
  double B;
  double Bi;
  mp_limb_t f;

  /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
     zero or infinity. */
  if (x != x || x == x * 0.5)
    {
      r->_mp_size = 0;
      return;
    }

  sign = x < 0.0 ;
  if (sign)
    x = - x;

  if (x < 1.0)
    {
      r->_mp_size = 0;
      return;
    }
  B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
  Bi = 1.0 / B;
  for (rn = 1; x >= B; rn++)
    x *= Bi;

  rp = MPZ_REALLOC (r, rn);

  f = (mp_limb_t) x;
  x -= f;
  assert (x < 1.0);
  i = rn-1;
  rp[i] = f;
  while (--i >= 0)
    {
      x = B * x;
      f = (mp_limb_t) x;
      x -= f;
      assert (x < 1.0);
      rp[i] = f;
    }

  r->_mp_size = sign ? - rn : rn;
}

void
mpz_init_set_d (mpz_t r, double x)
{
  mpz_init (r);
  mpz_set_d (r, x);
}

double
mpz_get_d (const mpz_t u)
{
  int m;
  mp_limb_t l;
  mp_size_t un;
  double x;
  double B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);

  un = GMP_ABS (u->_mp_size);

  if (un == 0)
    return 0.0;

  l = u->_mp_d[--un];
  gmp_clz (m, l);
  m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
  if (m < 0)
    l &= GMP_LIMB_MAX << -m;

  for (x = l; --un >= 0;)
    {
      x = B*x;
      if (m > 0) {
    l = u->_mp_d[un];
    m -= GMP_LIMB_BITS;
    if (m < 0)
      l &= GMP_LIMB_MAX << -m;
    x += l;
      }
    }

  if (u->_mp_size < 0)
    x = -x;

  return x;
}

int
mpz_cmpabs_d (const mpz_t x, double d)
{
  mp_size_t xn;
  double B, Bi;
  mp_size_t i;

  xn = x->_mp_size;
  d = GMP_ABS (d);

  if (xn != 0)
    {
      xn = GMP_ABS (xn);

      B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
      Bi = 1.0 / B;

      /* Scale d so it can be compared with the top limb. */
      for (i = 1; i < xn; i++)
    d *= Bi;

      if (d >= B)
    return -1;

      /* Compare floor(d) to top limb, subtract and cancel when equal. */
      for (i = xn; i-- > 0;)
    {
      mp_limb_t f, xl;

      f = (mp_limb_t) d;
      xl = x->_mp_d[i];
      if (xl > f)
        return 1;
      else if (xl < f)
        return -1;
      d = B * (d - f);
    }
    }
  return - (d > 0.0);
}

int
mpz_cmp_d (const mpz_t x, double d)
{
  if (x->_mp_size < 0)
    {
      if (d >= 0.0)
    return -1;
      else
    return -mpz_cmpabs_d (x, d);
    }
  else
    {
      if (d < 0.0)
    return 1;
      else
    return mpz_cmpabs_d (x, d);
    }
}


/* MPZ comparisons and the like. */
int
mpz_sgn (const mpz_t u)
{
  return GMP_CMP (u->_mp_size, 0);
}

int
mpz_cmp_si (const mpz_t u, long v)
{
  mp_size_t usize = u->_mp_size;

  if (v >= 0)
    return mpz_cmp_ui (u, v);
  else if (usize >= 0)
    return 1;
  else
    return - mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, v));
}

int
mpz_cmp_ui (const mpz_t u, unsigned long v)
{
  mp_size_t usize = u->_mp_size;

  if (usize < 0)
    return -1;
  else
    return mpz_cmpabs_ui (u, v);
}

int
mpz_cmp (const mpz_t a, const mpz_t b)
{
  mp_size_t asize = a->_mp_size;
  mp_size_t bsize = b->_mp_size;

  if (asize != bsize)
    return (asize < bsize) ? -1 : 1;
  else if (asize >= 0)
    return mpn_cmp (a->_mp_d, b->_mp_d, asize);
  else
    return mpn_cmp (b->_mp_d, a->_mp_d, -asize);
}

int
mpz_cmpabs_ui (const mpz_t u, unsigned long v)
{
  mp_size_t un = GMP_ABS (u->_mp_size);

  if (! mpn_absfits_ulong_p (u->_mp_d, un))
    return 1;
  else
    {
      unsigned long uu = mpz_get_ui (u);
      return GMP_CMP(uu, v);
    }
}

int
mpz_cmpabs (const mpz_t u, const mpz_t v)
{
  return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
           v->_mp_d, GMP_ABS (v->_mp_size));
}

void
mpz_abs (mpz_t r, const mpz_t u)
{
  mpz_set (r, u);
  r->_mp_size = GMP_ABS (r->_mp_size);
}

void
mpz_neg (mpz_t r, const mpz_t u)
{
  mpz_set (r, u);
  r->_mp_size = -r->_mp_size;
}

void
mpz_swap (mpz_t u, mpz_t v)
{
  MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
  MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size);
}


/* MPZ addition and subtraction */


void
mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
{
  mpz_t bb;
  mpz_init_set_ui (bb, b);
  mpz_add (r, a, bb);
  mpz_clear (bb);
}

void
mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
{
  mpz_ui_sub (r, b, a);
  mpz_neg (r, r);
}

void
mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
{
  mpz_neg (r, b);
  mpz_add_ui (r, r, a);
}

static mp_size_t
mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
{
  mp_size_t an = GMP_ABS (a->_mp_size);
  mp_size_t bn = GMP_ABS (b->_mp_size);
  mp_ptr rp;
  mp_limb_t cy;

  if (an < bn)
    {
      MPZ_SRCPTR_SWAP (a, b);
      MP_SIZE_T_SWAP (an, bn);
    }

  rp = MPZ_REALLOC (r, an + 1);
  cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);

  rp[an] = cy;

  return an + cy;
}

static mp_size_t
mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
{
  mp_size_t an = GMP_ABS (a->_mp_size);
  mp_size_t bn = GMP_ABS (b->_mp_size);
  int cmp;
  mp_ptr rp;

  cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
  if (cmp > 0)
    {
      rp = MPZ_REALLOC (r, an);
      gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
      return mpn_normalized_size (rp, an);
    }
  else if (cmp < 0)
    {
      rp = MPZ_REALLOC (r, bn);
      gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
      return -mpn_normalized_size (rp, bn);
    }
  else
    return 0;
}

void
mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
{
  mp_size_t rn;

  if ( (a->_mp_size ^ b->_mp_size) >= 0)
    rn = mpz_abs_add (r, a, b);
  else
    rn = mpz_abs_sub (r, a, b);

  r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
}

void
mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
{
  mp_size_t rn;

  if ( (a->_mp_size ^ b->_mp_size) >= 0)
    rn = mpz_abs_sub (r, a, b);
  else
    rn = mpz_abs_add (r, a, b);

  r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
}


/* MPZ multiplication */
void
mpz_mul_si (mpz_t r, const mpz_t u, long int v)
{
  if (v < 0)
    {
      mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
      mpz_neg (r, r);
    }
  else
    mpz_mul_ui (r, u, v);
}

void
mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
{
  mpz_t vv;
  mpz_init_set_ui (vv, v);
  mpz_mul (r, u, vv);
  mpz_clear (vv);
  return;
}

void
mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
{
  int sign;
  mp_size_t un, vn, rn;
  mpz_t t;
  mp_ptr tp;

  un = u->_mp_size;
  vn = v->_mp_size;

  if (un == 0 || vn == 0)
    {
      r->_mp_size = 0;
      return;
    }

  sign = (un ^ vn) < 0;

  un = GMP_ABS (un);
  vn = GMP_ABS (vn);

  mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);

  tp = t->_mp_d;
  if (un >= vn)
    mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
  else
    mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);

  rn = un + vn;
  rn -= tp[rn-1] == 0;

  t->_mp_size = sign ? - rn : rn;
  mpz_swap (r, t);
  mpz_clear (t);
}

void
mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
{
  mp_size_t un, rn;
  mp_size_t limbs;
  unsigned shift;
  mp_ptr rp;

  un = GMP_ABS (u->_mp_size);
  if (un == 0)
    {
      r->_mp_size = 0;
      return;
    }

  limbs = bits / GMP_LIMB_BITS;
  shift = bits % GMP_LIMB_BITS;

  rn = un + limbs + (shift > 0);
  rp = MPZ_REALLOC (r, rn);
  if (shift > 0)
    {
      mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
      rp[rn-1] = cy;
      rn -= (cy == 0);
    }
  else
    mpn_copyd (rp + limbs, u->_mp_d, un);

  mpn_zero (rp, limbs);

  r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
}

void
mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v)
{
  mpz_t t;
  mpz_init_set_ui (t, v);
  mpz_mul (t, u, t);
  mpz_add (r, r, t);
  mpz_clear (t);
}

void
mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v)
{
  mpz_t t;
  mpz_init_set_ui (t, v);
  mpz_mul (t, u, t);
  mpz_sub (r, r, t);
  mpz_clear (t);
}

void
mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v)
{
  mpz_t t;
  mpz_init (t);
  mpz_mul (t, u, v);
  mpz_add (r, r, t);
  mpz_clear (t);
}

void
mpz_submul (mpz_t r, const mpz_t u, const mpz_t v)
{
  mpz_t t;
  mpz_init (t);
  mpz_mul (t, u, v);
  mpz_sub (r, r, t);
  mpz_clear (t);
}


/* MPZ division */
enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };

/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
static int
mpz_div_qr (mpz_t q, mpz_t r,
        const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
{
  mp_size_t ns, ds, nn, dn, qs;
  ns = n->_mp_size;
  ds = d->_mp_size;

  if (ds == 0)
    gmp_die("mpz_div_qr: Divide by zero.");

  if (ns == 0)
    {
      if (q)
    q->_mp_size = 0;
      if (r)
    r->_mp_size = 0;
      return 0;
    }

  nn = GMP_ABS (ns);
  dn = GMP_ABS (ds);

  qs = ds ^ ns;

  if (nn < dn)
    {
      if (mode == GMP_DIV_CEIL && qs >= 0)
    {
      /* q = 1, r = n - d */
      if (r)
        mpz_sub (r, n, d);
      if (q)
        mpz_set_ui (q, 1);
    }
      else if (mode == GMP_DIV_FLOOR && qs < 0)
    {
      /* q = -1, r = n + d */
      if (r)
        mpz_add (r, n, d);
      if (q)
        mpz_set_si (q, -1);
    }
      else
    {
      /* q = 0, r = d */
      if (r)
        mpz_set (r, n);
      if (q)
        q->_mp_size = 0;
    }
      return 1;
    }
  else
    {
      mp_ptr np, qp;
      mp_size_t qn, rn;
      mpz_t tq, tr;

      mpz_init_set (tr, n);
      np = tr->_mp_d;

      qn = nn - dn + 1;

      if (q)
    {
      mpz_init2 (tq, qn * GMP_LIMB_BITS);
      qp = tq->_mp_d;
    }
      else
    qp = NULL;

      mpn_div_qr (qp, np, nn, d->_mp_d, dn);

      if (qp)
    {
      qn -= (qp[qn-1] == 0);

      tq->_mp_size = qs < 0 ? -qn : qn;
    }
      rn = mpn_normalized_size (np, dn);
      tr->_mp_size = ns < 0 ? - rn : rn;

      if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
    {
      if (q)
        mpz_sub_ui (tq, tq, 1);
      if (r)
        mpz_add (tr, tr, d);
    }
      else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
    {
      if (q)
        mpz_add_ui (tq, tq, 1);
      if (r)
        mpz_sub (tr, tr, d);
    }

      if (q)
    {
      mpz_swap (tq, q);
      mpz_clear (tq);
    }
      if (r)
    mpz_swap (tr, r);

      mpz_clear (tr);

      return rn != 0;
    }
}

void
mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
}

void
mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
}

void
mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
}

void
mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
}

void
mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
}

void
mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
}

void
mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
}

void
mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
}

void
mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
}

void
mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
{
  mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL);
}

static void
mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
        enum mpz_div_round_mode mode)
{
  mp_size_t un, qn;
  mp_size_t limb_cnt;
  mp_ptr qp;
  int adjust;

  un = u->_mp_size;
  if (un == 0)
    {
      q->_mp_size = 0;
      return;
    }
  limb_cnt = bit_index / GMP_LIMB_BITS;
  qn = GMP_ABS (un) - limb_cnt;
  bit_index %= GMP_LIMB_BITS;

  if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
    /* Note: Below, the final indexing at limb_cnt is valid because at
       that point we have qn > 0. */
    adjust = (qn <= 0
          || !mpn_zero_p (u->_mp_d, limb_cnt)
          || (u->_mp_d[limb_cnt]
          & (((mp_limb_t) 1 << bit_index) - 1)));
  else
    adjust = 0;

  if (qn <= 0)
    qn = 0;
  else
    {
      qp = MPZ_REALLOC (q, qn);

      if (bit_index != 0)
    {
      mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
      qn -= qp[qn - 1] == 0;
    }
      else
    {
      mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
    }
    }

  q->_mp_size = qn;

  if (adjust)
    mpz_add_ui (q, q, 1);
  if (un < 0)
    mpz_neg (q, q);
}

static void
mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
        enum mpz_div_round_mode mode)
{
  mp_size_t us, un, rn;
  mp_ptr rp;
  mp_limb_t mask;

  us = u->_mp_size;
  if (us == 0 || bit_index == 0)
    {
      r->_mp_size = 0;
      return;
    }
  rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
  assert (rn > 0);

  rp = MPZ_REALLOC (r, rn);
  un = GMP_ABS (us);

  mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);

  if (rn > un)
    {
      /* Quotient (with truncation) is zero, and remainder is
     non-zero */
      if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
    {
      /* Have to negate and sign extend. */
      mp_size_t i;

      gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un));
      for (i = un; i < rn - 1; i++)
        rp[i] = GMP_LIMB_MAX;

      rp[rn-1] = mask;
      us = -us;
    }
      else
    {
      /* Just copy */
      if (r != u)
        mpn_copyi (rp, u->_mp_d, un);

      rn = un;
    }
    }
  else
    {
      if (r != u)
    mpn_copyi (rp, u->_mp_d, rn - 1);

      rp[rn-1] = u->_mp_d[rn-1] & mask;

      if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
    {
      /* If r != 0, compute 2^{bit_count} - r. */
      mpn_neg (rp, rp, rn);

      rp[rn-1] &= mask;

      /* us is not used for anything else, so we can modify it
         here to indicate flipped sign. */
      us = -us;
    }
    }
  rn = mpn_normalized_size (rp, rn);
  r->_mp_size = us < 0 ? -rn : rn;
}

void
mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
  mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
}

void
mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
  mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
}

void
mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
  mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
}

void
mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
  mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
}

void
mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
  mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
}

void
mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
  mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
}

void
mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
{
  gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
}

int
mpz_divisible_p (const mpz_t n, const mpz_t d)
{
  return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
}

int
mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m)
{
  mpz_t t;
  int res;

  /* a == b (mod 0) iff a == b */
  if (mpz_sgn (m) == 0)
    return (mpz_cmp (a, b) == 0);

  mpz_init (t);
  mpz_sub (t, a, b);
  res = mpz_divisible_p (t, m);
  mpz_clear (t);

  return res;
}

static unsigned long
mpz_div_qr_ui (mpz_t q, mpz_t r,
           const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
{
  unsigned long ret;
  mpz_t rr, dd;

  mpz_init (rr);
  mpz_init_set_ui (dd, d);
  mpz_div_qr (q, rr, n, dd, mode);
  mpz_clear (dd);
  ret = mpz_get_ui (rr);

  if (r)
    mpz_swap (r, rr);
  mpz_clear (rr);

  return ret;
}

unsigned long
mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
}

unsigned long
mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
}

unsigned long
mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
}

unsigned long
mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
}

unsigned long
mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
}

unsigned long
mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
}

unsigned long
mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
}
unsigned long
mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
}
unsigned long
mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
}

unsigned long
mpz_cdiv_ui (const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
}

unsigned long
mpz_fdiv_ui (const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
}

unsigned long
mpz_tdiv_ui (const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
}

unsigned long
mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
}

void
mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
{
  gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
}

int
mpz_divisible_ui_p (const mpz_t n, unsigned long d)
{
  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
}


/* GCD */
static mp_limb_t
mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
{
  unsigned shift;

  assert ( (u | v) > 0);

  if (u == 0)
    return v;
  else if (v == 0)
    return u;

  gmp_ctz (shift, u | v);

  u >>= shift;
  v >>= shift;

  if ( (u & 1) == 0)
    MP_LIMB_T_SWAP (u, v);

  while ( (v & 1) == 0)
    v >>= 1;

  while (u != v)
    {
      if (u > v)
    {
      u -= v;
      do
        u >>= 1;
      while ( (u & 1) == 0);
    }
      else
    {
      v -= u;
      do
        v >>= 1;
      while ( (v & 1) == 0);
    }
    }
  return u << shift;
}

unsigned long
mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
{
  mpz_t t;
  mpz_init_set_ui(t, v);
  mpz_gcd (t, u, t);
  if (v > 0)
    v = mpz_get_ui (t);

  if (g)
    mpz_swap (t, g);

  mpz_clear (t);

  return v;
}

static mp_bitcnt_t
mpz_make_odd (mpz_t r)
{
  mp_bitcnt_t shift;

  assert (r->_mp_size > 0);
  /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
  shift = mpn_scan1 (r->_mp_d, 0);
  mpz_tdiv_q_2exp (r, r, shift);

  return shift;
}

void
mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
{
  mpz_t tu, tv;
  mp_bitcnt_t uz, vz, gz;

  if (u->_mp_size == 0)
    {
      mpz_abs (g, v);
      return;
    }
  if (v->_mp_size == 0)
    {
      mpz_abs (g, u);
      return;
    }

  mpz_init (tu);
  mpz_init (tv);

  mpz_abs (tu, u);
  uz = mpz_make_odd (tu);
  mpz_abs (tv, v);
  vz = mpz_make_odd (tv);
  gz = GMP_MIN (uz, vz);

  if (tu->_mp_size < tv->_mp_size)
    mpz_swap (tu, tv);

  mpz_tdiv_r (tu, tu, tv);
  if (tu->_mp_size == 0)
    {
      mpz_swap (g, tv);
    }
  else
    for (;;)
      {
    int c;

    mpz_make_odd (tu);
    c = mpz_cmp (tu, tv);
    if (c == 0)
      {
        mpz_swap (g, tu);
        break;
      }
    if (c < 0)
      mpz_swap (tu, tv);

    if (tv->_mp_size == 1)
      {
        mp_limb_t *gp;

        mpz_tdiv_r (tu, tu, tv);
        gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */
        *gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]);

        g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */
        break;
      }
    mpz_sub (tu, tu, tv);
      }
  mpz_clear (tu);
  mpz_clear (tv);
  mpz_mul_2exp (g, g, gz);
}

void
mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
{
  mpz_t tu, tv, s0, s1, t0, t1;
  mp_bitcnt_t uz, vz, gz;
  mp_bitcnt_t power;

  if (u->_mp_size == 0)
    {
      /* g = 0 u + sgn(v) v */
      signed long sign = mpz_sgn (v);
      mpz_abs (g, v);
      if (s)
    s->_mp_size = 0;
      if (t)
    mpz_set_si (t, sign);
      return;
    }

  if (v->_mp_size == 0)
    {
      /* g = sgn(u) u + 0 v */
      signed long sign = mpz_sgn (u);
      mpz_abs (g, u);
      if (s)
    mpz_set_si (s, sign);
      if (t)
    t->_mp_size = 0;
      return;
    }

  mpz_init (tu);
  mpz_init (tv);
  mpz_init (s0);
  mpz_init (s1);
  mpz_init (t0);
  mpz_init (t1);

  mpz_abs (tu, u);
  uz = mpz_make_odd (tu);
  mpz_abs (tv, v);
  vz = mpz_make_odd (tv);
  gz = GMP_MIN (uz, vz);

  uz -= gz;
  vz -= gz;

  /* Cofactors corresponding to odd gcd. gz handled later. */
  if (tu->_mp_size < tv->_mp_size)
    {
      mpz_swap (tu, tv);
      MPZ_SRCPTR_SWAP (u, v);
      MPZ_PTR_SWAP (s, t);
      MP_BITCNT_T_SWAP (uz, vz);
    }

  /* Maintain
   *
   * u = t0 tu + t1 tv
   * v = s0 tu + s1 tv
   *
   * where u and v denote the inputs with common factors of two
   * eliminated, and det (s0, t0; s1, t1) = 2^p. Then
   *
   * 2^p tu =  s1 u - t1 v
   * 2^p tv = -s0 u + t0 v
   */

  /* After initial division, tu = q tv + tu', we have
   *
   * u = 2^uz (tu' + q tv)
   * v = 2^vz tv
   *
   * or
   *
   * t0 = 2^uz, t1 = 2^uz q
   * s0 = 0,    s1 = 2^vz
   */

  mpz_tdiv_qr (t1, tu, tu, tv);
  mpz_mul_2exp (t1, t1, uz);

  mpz_setbit (s1, vz);
  power = uz + vz;

  if (tu->_mp_size > 0)
    {
      mp_bitcnt_t shift;
      shift = mpz_make_odd (tu);
      mpz_setbit (t0, uz + shift);
      power += shift;

      for (;;)
    {
      int c;
      c = mpz_cmp (tu, tv);
      if (c == 0)
        break;

      if (c < 0)
        {
          /* tv = tv' + tu
           *
           * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
           * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */

          mpz_sub (tv, tv, tu);
          mpz_add (t0, t0, t1);
          mpz_add (s0, s0, s1);

          shift = mpz_make_odd (tv);
          mpz_mul_2exp (t1, t1, shift);
          mpz_mul_2exp (s1, s1, shift);
        }
      else
        {
          mpz_sub (tu, tu, tv);
          mpz_add (t1, t0, t1);
          mpz_add (s1, s0, s1);

          shift = mpz_make_odd (tu);
          mpz_mul_2exp (t0, t0, shift);
          mpz_mul_2exp (s0, s0, shift);
        }
      power += shift;
    }
    }
  else
    mpz_setbit (t0, uz);

  /* Now tv = odd part of gcd, and -s0 and t0 are corresponding
     cofactors. */

  mpz_mul_2exp (tv, tv, gz);
  mpz_neg (s0, s0);

  /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
     adjust cofactors, we need u / g and v / g */

  mpz_divexact (s1, v, tv);
  mpz_abs (s1, s1);
  mpz_divexact (t1, u, tv);
  mpz_abs (t1, t1);

  while (power-- > 0)
    {
      /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
      if (mpz_odd_p (s0) || mpz_odd_p (t0))
    {
      mpz_sub (s0, s0, s1);
      mpz_add (t0, t0, t1);
    }
      assert (mpz_even_p (t0) && mpz_even_p (s0));
      mpz_tdiv_q_2exp (s0, s0, 1);
      mpz_tdiv_q_2exp (t0, t0, 1);
    }

  /* Arrange so that |s| < |u| / 2g */
  mpz_add (s1, s0, s1);
  if (mpz_cmpabs (s0, s1) > 0)
    {
      mpz_swap (s0, s1);
      mpz_sub (t0, t0, t1);
    }
  if (u->_mp_size < 0)
    mpz_neg (s0, s0);
  if (v->_mp_size < 0)
    mpz_neg (t0, t0);

  mpz_swap (g, tv);
  if (s)
    mpz_swap (s, s0);
  if (t)
    mpz_swap (t, t0);

  mpz_clear (tu);
  mpz_clear (tv);
  mpz_clear (s0);
  mpz_clear (s1);
  mpz_clear (t0);
  mpz_clear (t1);
}

void
mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
{
  mpz_t g;

  if (u->_mp_size == 0 || v->_mp_size == 0)
    {
      r->_mp_size = 0;
      return;
    }

  mpz_init (g);

  mpz_gcd (g, u, v);
  mpz_divexact (g, u, g);
  mpz_mul (r, g, v);

  mpz_clear (g);
  mpz_abs (r, r);
}

void
mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
{
  if (v == 0 || u->_mp_size == 0)
    {
      r->_mp_size = 0;
      return;
    }

  v /= mpz_gcd_ui (NULL, u, v);
  mpz_mul_ui (r, u, v);

  mpz_abs (r, r);
}

int
mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
{
  mpz_t g, tr;
  int invertible;

  if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
    return 0;

  mpz_init (g);
  mpz_init (tr);

  mpz_gcdext (g, tr, NULL, u, m);
  invertible = (mpz_cmp_ui (g, 1) == 0);

  if (invertible)
    {
      if (tr->_mp_size < 0)
    {
      if (m->_mp_size >= 0)
        mpz_add (tr, tr, m);
      else
        mpz_sub (tr, tr, m);
    }
      mpz_swap (r, tr);
    }

  mpz_clear (g);
  mpz_clear (tr);
  return invertible;
}


/* Higher level operations (sqrt, pow and root) */

void
mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
{
  unsigned long bit;
  mpz_t tr;
  mpz_init_set_ui (tr, 1);

  bit = GMP_ULONG_HIGHBIT;
  do
    {
      mpz_mul (tr, tr, tr);
      if (e & bit)
    mpz_mul (tr, tr, b);
      bit >>= 1;
    }
  while (bit > 0);

  mpz_swap (r, tr);
  mpz_clear (tr);
}

void
mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
{
  mpz_t b;

  mpz_init_set_ui (b, blimb);
  mpz_pow_ui (r, b, e);
  mpz_clear (b);
}

void
mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
{
  mpz_t tr;
  mpz_t base;
  mp_size_t en, mn;
  mp_srcptr mp;
  struct gmp_div_inverse minv;
  unsigned shift;
  mp_ptr tp = NULL;

  en = GMP_ABS (e->_mp_size);
  mn = GMP_ABS (m->_mp_size);
  if (mn == 0)
    gmp_die ("mpz_powm: Zero modulo.");

  if (en == 0)
    {
      mpz_set_ui (r, mpz_cmpabs_ui (m, 1));
      return;
    }

  mp = m->_mp_d;
  mpn_div_qr_invert (&minv, mp, mn);
  shift = minv.shift;

  if (shift > 0)
    {
      /* To avoid shifts, we do all our reductions, except the final
     one, using a *normalized* m. */
      minv.shift = 0;

      tp = gmp_alloc_limbs (mn);
      gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
      mp = tp;
    }

  mpz_init (base);

  if (e->_mp_size < 0)
    {
      if (!mpz_invert (base, b, m))
    gmp_die ("mpz_powm: Negative exponent and non-invertible base.");
    }
  else
    {
      mp_size_t bn;
      mpz_abs (base, b);

      bn = base->_mp_size;
      if (bn >= mn)
    {
      mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
      bn = mn;
    }

      /* We have reduced the absolute value. Now take care of the
     sign. Note that we get zero represented non-canonically as
     m. */
      if (b->_mp_size < 0)
    {
      mp_ptr bp = MPZ_REALLOC (base, mn);
      gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
      bn = mn;
    }
      base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
    }
  mpz_init_set_ui (tr, 1);

  while (--en >= 0)
    {
      mp_limb_t w = e->_mp_d[en];
      mp_limb_t bit;

      bit = GMP_LIMB_HIGHBIT;
      do
    {
      mpz_mul (tr, tr, tr);
      if (w & bit)
        mpz_mul (tr, tr, base);
      if (tr->_mp_size > mn)
        {
          mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
          tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
        }
      bit >>= 1;
    }
      while (bit > 0);
    }

  /* Final reduction */
  if (tr->_mp_size >= mn)
    {
      minv.shift = shift;
      mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
      tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
    }
  if (tp)
    gmp_free_limbs (tp, mn);

  mpz_swap (r, tr);
  mpz_clear (tr);
  mpz_clear (base);
}

void
mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
{
  mpz_t e;

  mpz_init_set_ui (e, elimb);
  mpz_powm (r, b, e, m);
  mpz_clear (e);
}

/* x=trunc(y^(1/z)), r=y-x^z */
void
mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
{
  int sgn;
  mp_bitcnt_t bc;
  mpz_t t, u;

  sgn = y->_mp_size < 0;
  if ((~z & sgn) != 0)
    gmp_die ("mpz_rootrem: Negative argument, with even root.");
  if (z == 0)
    gmp_die ("mpz_rootrem: Zeroth root.");

  if (mpz_cmpabs_ui (y, 1) <= 0) {
    if (x)
      mpz_set (x, y);
    if (r)
      r->_mp_size = 0;
    return;
  }

  mpz_init (u);
  mpz_init (t);
  bc = (mpz_sizeinbase (y, 2) - 1) / z + 1;
  mpz_setbit (t, bc);

  if (z == 2) /* simplify sqrt loop: z-1 == 1 */
    do {
      mpz_swap (u, t);            /* u = x */
      mpz_tdiv_q (t, y, u);        /* t = y/x */
      mpz_add (t, t, u);        /* t = y/x + x */
      mpz_tdiv_q_2exp (t, t, 1);    /* x'= (y/x + x)/2 */
    } while (mpz_cmpabs (t, u) < 0);    /* |x'| < |x| */
  else /* z != 2 */ {
    mpz_t v;

    mpz_init (v);
    if (sgn)
      mpz_neg (t, t);

    do {
      mpz_swap (u, t);            /* u = x */
      mpz_pow_ui (t, u, z - 1);        /* t = x^(z-1) */
      mpz_tdiv_q (t, y, t);        /* t = y/x^(z-1) */
      mpz_mul_ui (v, u, z - 1);        /* v = x*(z-1) */
      mpz_add (t, t, v);        /* t = y/x^(z-1) + x*(z-1) */
      mpz_tdiv_q_ui (t, t, z);        /* x'=(y/x^(z-1) + x*(z-1))/z */
    } while (mpz_cmpabs (t, u) < 0);    /* |x'| < |x| */

    mpz_clear (v);
  }

  if (r) {
    mpz_pow_ui (t, u, z);
    mpz_sub (r, y, t);
  }
  if (x)
    mpz_swap (x, u);
  mpz_clear (u);
  mpz_clear (t);
}

int
mpz_root (mpz_t x, const mpz_t y, unsigned long z)
{
  int res;
  mpz_t r;

  mpz_init (r);
  mpz_rootrem (x, r, y, z);
  res = r->_mp_size == 0;
  mpz_clear (r);

  return res;
}

/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
void
mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
{
  mpz_rootrem (s, r, u, 2);
}

void
mpz_sqrt (mpz_t s, const mpz_t u)
{
  mpz_rootrem (s, NULL, u, 2);
}

int
mpz_perfect_square_p (const mpz_t u)
{
  if (u->_mp_size <= 0)
    return (u->_mp_size == 0);
  else
    return mpz_root (NULL, u, 2);
}

int
mpn_perfect_square_p (mp_srcptr p, mp_size_t n)
{
  mpz_t t;

  assert (n > 0);
  assert (p [n-1] != 0);
  return mpz_root (NULL, mpz_roinit_normal_n (t, p, n), 2);
}

mp_size_t
mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n)
{
  mpz_t s, r, u;
  mp_size_t res;

  assert (n > 0);
  assert (p [n-1] != 0);

  mpz_init (r);
  mpz_init (s);
  mpz_rootrem (s, r, mpz_roinit_normal_n (u, p, n), 2);

  assert (s->_mp_size == (n+1)/2);
  mpn_copyd (sp, s->_mp_d, s->_mp_size);
  mpz_clear (s);
  res = r->_mp_size;
  if (rp)
    mpn_copyd (rp, r->_mp_d, res);
  mpz_clear (r);
  return res;
}

/* Combinatorics */

void
mpz_mfac_uiui (mpz_t x, unsigned long n, unsigned long m)
{
  mpz_set_ui (x, n + (n == 0));
  if (m + 1 < 2) return;
  while (n > m + 1)
    mpz_mul_ui (x, x, n -= m);
}

void
mpz_2fac_ui (mpz_t x, unsigned long n)
{
  mpz_mfac_uiui (x, n, 2);
}

void
mpz_fac_ui (mpz_t x, unsigned long n)
{
  mpz_mfac_uiui (x, n, 1);
}

void
mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
{
  mpz_t t;

  mpz_set_ui (r, k <= n);

  if (k > (n >> 1))
    k = (k <= n) ? n - k : 0;

  mpz_init (t);
  mpz_fac_ui (t, k);

  for (; k > 0; --k)
    mpz_mul_ui (r, r, n--);

  mpz_divexact (r, r, t);
  mpz_clear (t);
}


/* Primality testing */

/* Computes Kronecker (a/b) with odd b, a!=0 and GCD(a,b) = 1 */
/* Adapted from JACOBI_BASE_METHOD==4 in mpn/generic/jacbase.c */
static int
gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
{
  int c, bit = 0;

  assert (b & 1);
  assert (a != 0);
  /* assert (mpn_gcd_11 (a, b) == 1); */

  /* Below, we represent a and b shifted right so that the least
     significant one bit is implicit. */
  b >>= 1;

  gmp_ctz(c, a);
  a >>= 1;

  for (;;)
    {
      a >>= c;
      /* (2/b) = -1 if b = 3 or 5 mod 8 */
      bit ^= c & (b ^ (b >> 1));
      if (a < b)
    {
      if (a == 0)
        return bit & 1 ? -1 : 1;
      bit ^= a & b;
      a = b - a;
      b -= a;
    }
      else
    {
      a -= b;
      assert (a != 0);
    }

      gmp_ctz(c, a);
      ++c;
    }
}

static void
gmp_lucas_step_k_2k (mpz_t V, mpz_t Qk, const mpz_t n)
{
  mpz_mod (Qk, Qk, n);
  /* V_{2k} <- V_k ^ 2 - 2Q^k */
  mpz_mul (V, V, V);
  mpz_submul_ui (V, Qk, 2);
  mpz_tdiv_r (V, V, n);
  /* Q^{2k} = (Q^k)^2 */
  mpz_mul (Qk, Qk, Qk);
}

/* Computes V_k, Q^k (mod n) for the Lucas' sequence */
/* with P=1, Q=Q; k = (n>>b0)|1. */
/* Requires an odd n > 4; b0 > 0; -2*Q must not overflow a long */
/* Returns (U_k == 0) and sets V=V_k and Qk=Q^k. */
static int
gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q,
           mp_bitcnt_t b0, const mpz_t n)
{
  mp_bitcnt_t bs;
  mpz_t U;
  int res;

  assert (b0 > 0);
  assert (Q <= - (LONG_MIN / 2));
  assert (Q >= - (LONG_MAX / 2));
  assert (mpz_cmp_ui (n, 4) > 0);
  assert (mpz_odd_p (n));

  mpz_init_set_ui (U, 1); /* U1 = 1 */
  mpz_set_ui (V, 1); /* V1 = 1 */
  mpz_set_si (Qk, Q);

  for (bs = mpz_sizeinbase (n, 2) - 1; --bs >= b0;)
    {
      /* U_{2k} <- U_k * V_k */
      mpz_mul (U, U, V);
      /* V_{2k} <- V_k ^ 2 - 2Q^k */
      /* Q^{2k} = (Q^k)^2 */
      gmp_lucas_step_k_2k (V, Qk, n);

      /* A step k->k+1 is performed if the bit in $n$ is 1    */
      /* mpz_tstbit(n,bs) or the bit is 0 in $n$ but    */
      /* should be 1 in $n+1$ (bs == b0)            */
      if (b0 == bs || mpz_tstbit (n, bs))
    {
      /* Q^{k+1} <- Q^k * Q */
      mpz_mul_si (Qk, Qk, Q);
      /* U_{k+1} <- (U_k + V_k) / 2 */
      mpz_swap (U, V); /* Keep in V the old value of U_k */
      mpz_add (U, U, V);
      /* We have to compute U/2, so we need an even value, */
      /* equivalent (mod n) */
      if (mpz_odd_p (U))
        mpz_add (U, U, n);
      mpz_tdiv_q_2exp (U, U, 1);
      /* V_{k+1} <-(D*U_k + V_k) / 2 =
            U_{k+1} + (D-1)/2*U_k = U_{k+1} - 2Q*U_k */
      mpz_mul_si (V, V, -2*Q);
      mpz_add (V, U, V);
      mpz_tdiv_r (V, V, n);
    }
      mpz_tdiv_r (U, U, n);
    }

  res = U->_mp_size == 0;
  mpz_clear (U);
  return res;
}

/* Performs strong Lucas' test on x, with parameters suggested */
/* for the BPSW test. Qk is only passed to recycle a variable. */
/* Requires GCD (x,6) = 1.*/
static int
gmp_stronglucas (const mpz_t x, mpz_t Qk)
{
  mp_bitcnt_t b0;
  mpz_t V, n;
  mp_limb_t maxD, D; /* The absolute value is stored. */
  long Q;
  mp_limb_t tl;

  /* Test on the absolute value. */
  mpz_roinit_normal_n (n, x->_mp_d, GMP_ABS (x->_mp_size));

  assert (mpz_odd_p (n));
  /* assert (mpz_gcd_ui (NULL, n, 6) == 1); */
  if (mpz_root (Qk, n, 2))
    return 0; /* A square is composite. */

  /* Check Ds up to square root (in case, n is prime)
     or avoid overflows */
  maxD = (Qk->_mp_size == 1) ? Qk->_mp_d [0] - 1 : GMP_LIMB_MAX;

  D = 3;
  /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */
  /* For those Ds we have (D/n) = (n/|D|) */
  do
    {
      if (D >= maxD)
    return 1 + (D != GMP_LIMB_MAX); /* (1 + ! ~ D) */
      D += 2;
      tl = mpz_tdiv_ui (n, D);
      if (tl == 0)
    return 0;
    }
  while (gmp_jacobi_coprime (tl, D) == 1);

  mpz_init (V);

  /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
  b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX);
  /* b0 = mpz_scan0 (n, 0); */

  /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
  Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);

  if (! gmp_lucas_mod (V, Qk, Q, b0, n))    /* If Ud != 0 */
    while (V->_mp_size != 0 && --b0 != 0)    /* while Vk != 0 */
      /* V <- V ^ 2 - 2Q^k */
      /* Q^{2k} = (Q^k)^2 */
      gmp_lucas_step_k_2k (V, Qk, n);

  mpz_clear (V);
  return (b0 != 0);
}

static int
gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
         const mpz_t q, mp_bitcnt_t k)
{
  assert (k > 0);

  /* Caller must initialize y to the base. */
  mpz_powm (y, y, q, n);

  if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
    return 1;

  while (--k > 0)
    {
      mpz_powm_ui (y, y, 2, n);
      if (mpz_cmp (y, nm1) == 0)
    return 1;
    }
  return 0;
}

/* This product is 0xc0cfd797, and fits in 32 bits. */
#define GMP_PRIME_PRODUCT \
  (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL)

/* Bit (p+1)/2 is set, for each odd prime <= 61 */
#define GMP_PRIME_MASK 0xc96996dcUL

int
mpz_probab_prime_p (const mpz_t n, int reps)
{
  mpz_t nm1;
  mpz_t q;
  mpz_t y;
  mp_bitcnt_t k;
  int is_prime;
  int j;

  /* Note that we use the absolute value of n only, for compatibility
     with the real GMP. */
  if (mpz_even_p (n))
    return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0;

  /* Above test excludes n == 0 */
  assert (n->_mp_size != 0);

  if (mpz_cmpabs_ui (n, 64) < 0)
    return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2;

  if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1)
    return 0;

  /* All prime factors are >= 31. */
  if (mpz_cmpabs_ui (n, 31*31) < 0)
    return 2;

  mpz_init (nm1);
  mpz_init (q);

  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
  mpz_abs (nm1, n);
  nm1->_mp_d[0] -= 1;
  /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
  k = mpn_scan1 (nm1->_mp_d, 0);
  mpz_tdiv_q_2exp (q, nm1, k);

  /* BPSW test */
  mpz_init_set_ui (y, 2);
  is_prime = gmp_millerrabin (n, nm1, y, q, k) && gmp_stronglucas (n, y);
  reps -= 24; /* skip the first 24 repetitions */

  /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] =
     j^2 + j + 41 using Euler's polynomial. We potentially stop early,
     if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps >
     30 (a[30] == 971 > 31*31 == 961). */

  for (j = 0; is_prime & (j < reps); j++)
    {
      mpz_set_ui (y, (unsigned long) j*j+j+41);
      if (mpz_cmp (y, nm1) >= 0)
    {
      /* Don't try any further bases. This "early" break does not affect
         the result for any reasonable reps value (<=5000 was tested) */
      assert (j >= 30);
      break;
    }
      is_prime = gmp_millerrabin (n, nm1, y, q, k);
    }
  mpz_clear (nm1);
  mpz_clear (q);
  mpz_clear (y);

  return is_prime;
}


/* Logical operations and bit manipulation. */

/* Numbers are treated as if represented in two's complement (and
   infinitely sign extended). For a negative values we get the two's
   complement from -x = ~x + 1, where ~ is bitwise complement.
   Negation transforms

     xxxx10...0

   into

     yyyy10...0

   where yyyy is the bitwise complement of xxxx. So least significant
   bits, up to and including the first one bit, are unchanged, and
   the more significant bits are all complemented.

   To change a bit from zero to one in a negative number, subtract the
   corresponding power of two from the absolute value. This can never
   underflow. To change a bit from one to zero, add the corresponding
   power of two, and this might overflow. E.g., if x = -001111, the
   two's complement is 110001. Clearing the least significant bit, we
   get two's complement 110000, and -010000. */

int
mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
{
  mp_size_t limb_index;
  unsigned shift;
  mp_size_t ds;
  mp_size_t dn;
  mp_limb_t w;
  int bit;

  ds = d->_mp_size;
  dn = GMP_ABS (ds);
  limb_index = bit_index / GMP_LIMB_BITS;
  if (limb_index >= dn)
    return ds < 0;

  shift = bit_index % GMP_LIMB_BITS;
  w = d->_mp_d[limb_index];
  bit = (w >> shift) & 1;

  if (ds < 0)
    {
      /* d < 0. Check if any of the bits below is set: If so, our bit
     must be complemented. */
      if (shift > 0 && (mp_limb_t) (w << (GMP_LIMB_BITS - shift)) > 0)
    return bit ^ 1;
      while (--limb_index >= 0)
    if (d->_mp_d[limb_index] > 0)
      return bit ^ 1;
    }
  return bit;
}

static void
mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
{
  mp_size_t dn, limb_index;
  mp_limb_t bit;
  mp_ptr dp;

  dn = GMP_ABS (d->_mp_size);

  limb_index = bit_index / GMP_LIMB_BITS;
  bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);

  if (limb_index >= dn)
    {
      mp_size_t i;
      /* The bit should be set outside of the end of the number.
     We have to increase the size of the number. */
      dp = MPZ_REALLOC (d, limb_index + 1);

      dp[limb_index] = bit;
      for (i = dn; i < limb_index; i++)
    dp[i] = 0;
      dn = limb_index + 1;
    }
  else
    {
      mp_limb_t cy;

      dp = d->_mp_d;

      cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
      if (cy > 0)
    {
      dp = MPZ_REALLOC (d, dn + 1);
      dp[dn++] = cy;
    }
    }

  d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
}

static void
mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
{
  mp_size_t dn, limb_index;
  mp_ptr dp;
  mp_limb_t bit;

  dn = GMP_ABS (d->_mp_size);
  dp = d->_mp_d;

  limb_index = bit_index / GMP_LIMB_BITS;
  bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);

  assert (limb_index < dn);

  gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
                 dn - limb_index, bit));
  dn = mpn_normalized_size (dp, dn);
  d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
}

void
mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
{
  if (!mpz_tstbit (d, bit_index))
    {
      if (d->_mp_size >= 0)
    mpz_abs_add_bit (d, bit_index);
      else
    mpz_abs_sub_bit (d, bit_index);
    }
}

void
mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
{
  if (mpz_tstbit (d, bit_index))
    {
      if (d->_mp_size >= 0)
    mpz_abs_sub_bit (d, bit_index);
      else
    mpz_abs_add_bit (d, bit_index);
    }
}

void
mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
{
  if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
    mpz_abs_sub_bit (d, bit_index);
  else
    mpz_abs_add_bit (d, bit_index);
}

void
mpz_com (mpz_t r, const mpz_t u)
{
  mpz_add_ui (r, u, 1);
  mpz_neg (r, r);
}

void
mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
{
  mp_size_t un, vn, rn, i;
  mp_ptr up, vp, rp;

  mp_limb_t ux, vx, rx;
  mp_limb_t uc, vc, rc;
  mp_limb_t ul, vl, rl;

  un = GMP_ABS (u->_mp_size);
  vn = GMP_ABS (v->_mp_size);
  if (un < vn)
    {
      MPZ_SRCPTR_SWAP (u, v);
      MP_SIZE_T_SWAP (un, vn);
    }
  if (vn == 0)
    {
      r->_mp_size = 0;
      return;
    }

  uc = u->_mp_size < 0;
  vc = v->_mp_size < 0;
  rc = uc & vc;

  ux = -uc;
  vx = -vc;
  rx = -rc;

  /* If the smaller input is positive, higher limbs don't matter. */
  rn = vx ? un : vn;

  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);

  up = u->_mp_d;
  vp = v->_mp_d;

  i = 0;
  do
    {
      ul = (up[i] ^ ux) + uc;
      uc = ul < uc;

      vl = (vp[i] ^ vx) + vc;
      vc = vl < vc;

      rl = ( (ul & vl) ^ rx) + rc;
      rc = rl < rc;
      rp[i] = rl;
    }
  while (++i < vn);
  assert (vc == 0);

  for (; i < rn; i++)
    {
      ul = (up[i] ^ ux) + uc;
      uc = ul < uc;

      rl = ( (ul & vx) ^ rx) + rc;
      rc = rl < rc;
      rp[i] = rl;
    }
  if (rc)
    rp[rn++] = rc;
  else
    rn = mpn_normalized_size (rp, rn);

  r->_mp_size = rx ? -rn : rn;
}

void
mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
{
  mp_size_t un, vn, rn, i;
  mp_ptr up, vp, rp;

  mp_limb_t ux, vx, rx;
  mp_limb_t uc, vc, rc;
  mp_limb_t ul, vl, rl;

  un = GMP_ABS (u->_mp_size);
  vn = GMP_ABS (v->_mp_size);
  if (un < vn)
    {
      MPZ_SRCPTR_SWAP (u, v);
      MP_SIZE_T_SWAP (un, vn);
    }
  if (vn == 0)
    {
      mpz_set (r, u);
      return;
    }

  uc = u->_mp_size < 0;
  vc = v->_mp_size < 0;
  rc = uc | vc;

  ux = -uc;
  vx = -vc;
  rx = -rc;

  /* If the smaller input is negative, by sign extension higher limbs
     don't matter. */
  rn = vx ? vn : un;

  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);

  up = u->_mp_d;
  vp = v->_mp_d;

  i = 0;
  do
    {
      ul = (up[i] ^ ux) + uc;
      uc = ul < uc;

      vl = (vp[i] ^ vx) + vc;
      vc = vl < vc;

      rl = ( (ul | vl) ^ rx) + rc;
      rc = rl < rc;
      rp[i] = rl;
    }
  while (++i < vn);
  assert (vc == 0);

  for (; i < rn; i++)
    {
      ul = (up[i] ^ ux) + uc;
      uc = ul < uc;

      rl = ( (ul | vx) ^ rx) + rc;
      rc = rl < rc;
      rp[i] = rl;
    }
  if (rc)
    rp[rn++] = rc;
  else
    rn = mpn_normalized_size (rp, rn);

  r->_mp_size = rx ? -rn : rn;
}

void
mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
{
  mp_size_t un, vn, i;
  mp_ptr up, vp, rp;

  mp_limb_t ux, vx, rx;
  mp_limb_t uc, vc, rc;
  mp_limb_t ul, vl, rl;

  un = GMP_ABS (u->_mp_size);
  vn = GMP_ABS (v->_mp_size);
  if (un < vn)
    {
      MPZ_SRCPTR_SWAP (u, v);
      MP_SIZE_T_SWAP (un, vn);
    }
  if (vn == 0)
    {
      mpz_set (r, u);
      return;
    }

  uc = u->_mp_size < 0;
  vc = v->_mp_size < 0;
  rc = uc ^ vc;

  ux = -uc;
  vx = -vc;
  rx = -rc;

  rp = MPZ_REALLOC (r, un + (mp_size_t) rc);

  up = u->_mp_d;
  vp = v->_mp_d;

  i = 0;
  do
    {
      ul = (up[i] ^ ux) + uc;
      uc = ul < uc;

      vl = (vp[i] ^ vx) + vc;
      vc = vl < vc;

      rl = (ul ^ vl ^ rx) + rc;
      rc = rl < rc;
      rp[i] = rl;
    }
  while (++i < vn);
  assert (vc == 0);

  for (; i < un; i++)
    {
      ul = (up[i] ^ ux) + uc;
      uc = ul < uc;

      rl = (ul ^ ux) + rc;
      rc = rl < rc;
      rp[i] = rl;
    }
  if (rc)
    rp[un++] = rc;
  else
    un = mpn_normalized_size (rp, un);

  r->_mp_size = rx ? -un : un;
}

static unsigned
gmp_popcount_limb (mp_limb_t x)
{
  unsigned c;

  /* Do 16 bits at a time, to avoid limb-sized constants. */
  int LOCAL_SHIFT_BITS = 16;
  for (c = 0; x > 0;)
    {
      unsigned w = x - ((x >> 1) & 0x5555);
      w = ((w >> 2) & 0x3333) + (w & 0x3333);
      w =  (w >> 4) + w;
      w = ((w >> 8) & 0x000f) + (w & 0x000f);
      c += w;
      if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)
    x >>= LOCAL_SHIFT_BITS;
      else
    x = 0;
    }
  return c;
}

mp_bitcnt_t
mpn_popcount (mp_srcptr p, mp_size_t n)
{
  mp_size_t i;
  mp_bitcnt_t c;

  for (c = 0, i = 0; i < n; i++)
    c += gmp_popcount_limb (p[i]);

  return c;
}

mp_bitcnt_t
mpz_popcount (const mpz_t u)
{
  mp_size_t un;

  un = u->_mp_size;

  if (un < 0)
    return ~(mp_bitcnt_t) 0;

  return mpn_popcount (u->_mp_d, un);
}

mp_bitcnt_t
mpz_hamdist (const mpz_t u, const mpz_t v)
{
  mp_size_t un, vn, i;
  mp_limb_t uc, vc, ul, vl, comp;
  mp_srcptr up, vp;
  mp_bitcnt_t c;

  un = u->_mp_size;
  vn = v->_mp_size;

  if ( (un ^ vn) < 0)
    return ~(mp_bitcnt_t) 0;

  comp = - (uc = vc = (un < 0));
  if (uc)
    {
      assert (vn < 0);
      un = -un;
      vn = -vn;
    }

  up = u->_mp_d;
  vp = v->_mp_d;

  if (un < vn)
    MPN_SRCPTR_SWAP (up, un, vp, vn);

  for (i = 0, c = 0; i < vn; i++)
    {
      ul = (up[i] ^ comp) + uc;
      uc = ul < uc;

      vl = (vp[i] ^ comp) + vc;
      vc = vl < vc;

      c += gmp_popcount_limb (ul ^ vl);
    }
  assert (vc == 0);

  for (; i < un; i++)
    {
      ul = (up[i] ^ comp) + uc;
      uc = ul < uc;

      c += gmp_popcount_limb (ul ^ comp);
    }

  return c;
}

mp_bitcnt_t
mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
{
  mp_ptr up;
  mp_size_t us, un, i;
  mp_limb_t limb, ux;

  us = u->_mp_size;
  un = GMP_ABS (us);
  i = starting_bit / GMP_LIMB_BITS;

  /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
     for u<0. Notice this test picks up any u==0 too. */
  if (i >= un)
    return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);

  up = u->_mp_d;
  ux = 0;
  limb = up[i];

  if (starting_bit != 0)
    {
      if (us < 0)
    {
      ux = mpn_zero_p (up, i);
      limb = ~ limb + ux;
      ux = - (mp_limb_t) (limb >= ux);
    }

      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
      limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
    }

  return mpn_common_scan (limb, i, up, un, ux);
}

mp_bitcnt_t
mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
{
  mp_ptr up;
  mp_size_t us, un, i;
  mp_limb_t limb, ux;

  us = u->_mp_size;
  ux = - (mp_limb_t) (us >= 0);
  un = GMP_ABS (us);
  i = starting_bit / GMP_LIMB_BITS;

  /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
     u<0.  Notice this test picks up all cases of u==0 too. */
  if (i >= un)
    return (ux ? starting_bit : ~(mp_bitcnt_t) 0);

  up = u->_mp_d;
  limb = up[i] ^ ux;

  if (ux == 0)
    limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */

  /* Mask all bits before starting_bit, thus ignoring them. */
  limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);

  return mpn_common_scan (limb, i, up, un, ux);
}


/* MPZ base conversion. */

size_t
mpz_sizeinbase (const mpz_t u, int base)
{
  mp_size_t un, tn;
  mp_srcptr up;
  mp_ptr tp;
  mp_bitcnt_t bits;
  struct gmp_div_inverse bi;
  size_t ndigits;

  assert (base >= 2);
  assert (base <= 62);

  un = GMP_ABS (u->_mp_size);
  if (un == 0)
    return 1;

  up = u->_mp_d;

  bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
  switch (base)
    {
    case 2:
      return bits;
    case 4:
      return (bits + 1) / 2;
    case 8:
      return (bits + 2) / 3;
    case 16:
      return (bits + 3) / 4;
    case 32:
      return (bits + 4) / 5;
      /* FIXME: Do something more clever for the common case of base
     10. */
    }

  tp = gmp_alloc_limbs (un);
  mpn_copyi (tp, up, un);
  mpn_div_qr_1_invert (&bi, base);

  tn = un;
  ndigits = 0;
  do
    {
      ndigits++;
      mpn_div_qr_1_preinv (tp, tp, tn, &bi);
      tn -= (tp[tn-1] == 0);
    }
  while (tn > 0);

  gmp_free_limbs (tp, un);
  return ndigits;
}

char *
mpz_get_str (char *sp, int base, const mpz_t u)
{
  unsigned bits;
  const char *digits;
  mp_size_t un;
  size_t i, sn, osn;

  digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  if (base > 1)
    {
      if (base <= 36)
    digits = "0123456789abcdefghijklmnopqrstuvwxyz";
      else if (base > 62)
    return NULL;
    }
  else if (base >= -1)
    base = 10;
  else
    {
      base = -base;
      if (base > 36)
    return NULL;
    }

  sn = 1 + mpz_sizeinbase (u, base);
  if (!sp)
    {
      osn = 1 + sn;
      sp = (char *) gmp_alloc (osn);
    }
  else
    osn = 0;
  un = GMP_ABS (u->_mp_size);

  if (un == 0)
    {
      sp[0] = '0';
      sn = 1;
      goto ret;
    }

  i = 0;

  if (u->_mp_size < 0)
    sp[i++] = '-';

  bits = mpn_base_power_of_two_p (base);

  if (bits)
    /* Not modified in this case. */
    sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
  else
    {
      struct mpn_base_info info;
      mp_ptr tp;

      mpn_get_base_info (&info, base);
      tp = gmp_alloc_limbs (un);
      mpn_copyi (tp, u->_mp_d, un);

      sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
      gmp_free_limbs (tp, un);
    }

  for (; i < sn; i++)
    sp[i] = digits[(unsigned char) sp[i]];

ret:
  sp[sn] = '\0';
  if (osn && osn != sn + 1)
    sp = (char*) gmp_realloc (sp, osn, sn + 1);
  return sp;
}

int
mpz_set_str (mpz_t r, const char *sp, int base)
{
  unsigned bits, value_of_a;
  mp_size_t rn, alloc;
  mp_ptr rp;
  size_t dn, sn;
  int sign;
  unsigned char *dp;

  assert (base == 0 || (base >= 2 && base <= 62));

  while (isspace( (unsigned char) *sp))
    sp++;

  sign = (*sp == '-');
  sp += sign;

  if (base == 0)
    {
      if (sp[0] == '0')
    {
      if (sp[1] == 'x' || sp[1] == 'X')
        {
          base = 16;
          sp += 2;
        }
      else if (sp[1] == 'b' || sp[1] == 'B')
        {
          base = 2;
          sp += 2;
        }
      else
        base = 8;
    }
      else
    base = 10;
    }

  if (!*sp)
    {
      r->_mp_size = 0;
      return -1;
    }
  sn = strlen(sp);
  dp = (unsigned char *) gmp_alloc (sn);

  value_of_a = (base > 36) ? 36 : 10;
  for (dn = 0; *sp; sp++)
    {
      unsigned digit;

      if (isspace ((unsigned char) *sp))
    continue;
      else if (*sp >= '0' && *sp <= '9')
    digit = *sp - '0';
      else if (*sp >= 'a' && *sp <= 'z')
    digit = *sp - 'a' + value_of_a;
      else if (*sp >= 'A' && *sp <= 'Z')
    digit = *sp - 'A' + 10;
      else
    digit = base; /* fail */

      if (digit >= (unsigned) base)
    {
      gmp_free (dp, sn);
      r->_mp_size = 0;
      return -1;
    }

      dp[dn++] = digit;
    }

  if (!dn)
    {
      gmp_free (dp, sn);
      r->_mp_size = 0;
      return -1;
    }
  bits = mpn_base_power_of_two_p (base);

  if (bits > 0)
    {
      alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
      rp = MPZ_REALLOC (r, alloc);
      rn = mpn_set_str_bits (rp, dp, dn, bits);
    }
  else
    {
      struct mpn_base_info info;
      mpn_get_base_info (&info, base);
      alloc = (dn + info.exp - 1) / info.exp;
      rp = MPZ_REALLOC (r, alloc);
      rn = mpn_set_str_other (rp, dp, dn, base, &info);
      /* Normalization, needed for all-zero input. */
      assert (rn > 0);
      rn -= rp[rn-1] == 0;
    }
  assert (rn <= alloc);
  gmp_free (dp, sn);

  r->_mp_size = sign ? - rn : rn;

  return 0;
}

int
mpz_init_set_str (mpz_t r, const char *sp, int base)
{
  mpz_init (r);
  return mpz_set_str (r, sp, base);
}

size_t
mpz_out_str (FILE *stream, int base, const mpz_t x)
{
  char *str;
  size_t len, n;

  str = mpz_get_str (NULL, base, x);
  if (!str)
    return 0;
  len = strlen (str);
  n = fwrite (str, 1, len, stream);
  gmp_free (str, len + 1);
  return n;
}


static int
gmp_detect_endian (void)
{
  static const int i = 2;
  const unsigned char *p = (const unsigned char *) &i;
  return 1 - *p;
}

/* Import and export. Does not support nails. */
void
mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
        size_t nails, const void *src)
{
  const unsigned char *p;
  ptrdiff_t word_step;
  mp_ptr rp;
  mp_size_t rn;

  /* The current (partial) limb. */
  mp_limb_t limb;
  /* The number of bytes already copied to this limb (starting from
     the low end). */
  size_t bytes;
  /* The index where the limb should be stored, when completed. */
  mp_size_t i;

  if (nails != 0)
    gmp_die ("mpz_import: Nails not supported.");

  assert (order == 1 || order == -1);
  assert (endian >= -1 && endian <= 1);

  if (endian == 0)
    endian = gmp_detect_endian ();

  p = (unsigned char *) src;

  word_step = (order != endian) ? 2 * size : 0;

  /* Process bytes from the least significant end, so point p at the
     least significant word. */
  if (order == 1)
    {
      p += size * (count - 1);
      word_step = - word_step;
    }

  /* And at least significant byte of that word. */
  if (endian == 1)
    p += (size - 1);

  rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
  rp = MPZ_REALLOC (r, rn);

  for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
    {
      size_t j;
      for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
    {
      limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
      if (bytes == sizeof(mp_limb_t))
        {
          rp[i++] = limb;
          bytes = 0;
          limb = 0;
        }
    }
    }
  assert (i + (bytes > 0) == rn);
  if (limb != 0)
    rp[i++] = limb;
  else
    i = mpn_normalized_size (rp, i);

  r->_mp_size = i;
}

void *
mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
        size_t nails, const mpz_t u)
{
  size_t count;
  mp_size_t un;

  if (nails != 0)
    gmp_die ("mpz_export: Nails not supported.");

  assert (order == 1 || order == -1);
  assert (endian >= -1 && endian <= 1);
  assert (size > 0 || u->_mp_size == 0);

  un = u->_mp_size;
  count = 0;
  if (un != 0)
    {
      size_t k;
      unsigned char *p;
      ptrdiff_t word_step;
      /* The current (partial) limb. */
      mp_limb_t limb;
      /* The number of bytes left to do in this limb. */
      size_t bytes;
      /* The index where the limb was read. */
      mp_size_t i;

      un = GMP_ABS (un);

      /* Count bytes in top limb. */
      limb = u->_mp_d[un-1];
      assert (limb != 0);

      k = (GMP_LIMB_BITS <= CHAR_BIT);
      if (!k)
    {
      do {
        int LOCAL_CHAR_BIT = CHAR_BIT;
        k++; limb >>= LOCAL_CHAR_BIT;
      } while (limb != 0);
    }
      /* else limb = 0; */

      count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;

      if (!r)
    r = gmp_alloc (count * size);

      if (endian == 0)
    endian = gmp_detect_endian ();

      p = (unsigned char *) r;

      word_step = (order != endian) ? 2 * size : 0;

      /* Process bytes from the least significant end, so point p at the
     least significant word. */
      if (order == 1)
    {
      p += size * (count - 1);
      word_step = - word_step;
    }

      /* And at least significant byte of that word. */
      if (endian == 1)
    p += (size - 1);

      for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
    {
      size_t j;
      for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian)
        {
          if (sizeof (mp_limb_t) == 1)
        {
          if (i < un)
            *p = u->_mp_d[i++];
          else
            *p = 0;
        }
          else
        {
          int LOCAL_CHAR_BIT = CHAR_BIT;
          if (bytes == 0)
            {
              if (i < un)
            limb = u->_mp_d[i++];
              bytes = sizeof (mp_limb_t);
            }
          *p = limb;
          limb >>= LOCAL_CHAR_BIT;
          bytes--;
        }
        }
    }
      assert (i == un);
      assert (k == count);
    }

  if (countp)
    *countp = count;

  return r;
}

#413. 内存较小的电脑 题目资源

413interactor

#include <cstdio>
#include <iostream>
#include "testlib.h"

int main(int argc, char** argv) {
    registerTestlibCmd(argc, argv);
    registerGen(argc, argv, 1);
    int n = inf.readInt();
    int q = inf.readInt();
    int rangel = inf.readInt();
    int ranger = inf.readInt();
    printf("%d %d\n", n, q);
    auto arr = new long[n + 1]();
    for (int i = 1; i <= n; i++)
    {
        arr[i] = rnd.next(rangel, ranger);
        printf("%ld ", arr[i]);
        arr[i] += arr[i - 1];
    }
    printf("\n");
    auto l = new int[q], r = new int[q];
    long ans = 0;
    for (int i = 0; i < q; i++)
    {
        l[i] = rnd.next(1, n);
        r[i] = rnd.next(1, n);
        if (l[i] > r[i])
            std::swap(l[i], r[i]);
        printf("%d %d\n", l[i], r[i]);
        ans ^= arr[r[i]] - arr[l[i] - 1];
    }
    fflush(stdout);
    delete[] l;
    delete[] r;
    delete[] arr;
    if (ans == ouf.readLong())
        quitf(_ok, "The answer is %ld.", ans);
    quitf(_wa, "Wrong answer.");
}

#410. 倍数点更新 题目资源

410data

#include <ctime>
#include <fstream>
#include <random>
#include <string>
#include <vector>

int main() {
    using namespace std;

    random_device seed;
    mt19937 rnd(seed());
    uniform_int_distribution<long> nm_dist(1, 100000);
    uniform_real_distribution<double> qu_dist(0, 1);
    uniform_int_distribution<long> numtyp_dist(0, 3);
    uniform_int_distribution<long> qnum_dist(1, 1000000000);
    double query = 0.0;
    for (int t = 1; t < 25; t++, query += 0.04)
    {
        ofstream iout("./data/random" + to_string(t) + ".in");
        ofstream oout("./data/random" + to_string(t) + ".out");
        int64_t n = nm_dist(rnd), m = nm_dist(rnd);
        uniform_int_distribution<int64_t> lr_dist(1, n);
        uniform_int_distribution<int64_t> sk_dist(1, max<int>(log2(n), 1));
        uniform_real_distribution<double> num_dist(0, 1);
        uniform_int_distribution<int64_t> hi_dist(max<int>(log2(n), 1), n);
        uniform_int_distribution<int64_t> norm_dist(1, n);
        long numtyp = numtyp_dist(rnd);
        iout << n << ' ' << m << endl;
        vector<long> arr(n + 1, 0);
        while (m--)
        {
            if (qu_dist(rnd) < query)
            {
                long a, b = qnum_dist(rnd);
                switch (numtyp)
                {
                    case 0:
                        a = sk_dist(rnd);
                        break;
                    case 1:
                        a = pow(n, num_dist(rnd));
                        break;
                    case 2:
                        a = norm_dist(rnd);
                    default:
                        a = hi_dist(rnd);
                        break;
                }
                iout << 1 << ' ' << a << ' ' << b << endl;
                for (int i = 1; i * a <= n; i++)
                    arr[i * a] += b;
            }
            else
            {
                long a = lr_dist(rnd), b = lr_dist(rnd);
                if (a > b)
                    swap(a, b);
                iout << 2 << ' ' << a << ' ' << b << endl;
                long res = 0;
                for (long i = a; i <= b; i++)
                    res += arr[i];
                oout << res << endl;
            }
        }
    }
    return 0;
}

#411. C计划 题目资源

411std

#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;

const int MAXN = 1000000;
const int MAXT = 2 * MAXN;

int n, m, Q;
vector<int> G[MAXN + 5];
vector<int> T[MAXT + 5];
int dfn[MAXN + 5], low[MAXN + 5];
int stk[MAXN + 5], top;
int idx, bcc_cnt;
int comp[MAXT + 5];
int depth[MAXT + 5], sum[MAXT + 5];
int fa[MAXT + 5][21];
int LOG;

void tarjan(int u) {
    dfn[u] = low[u] = ++idx;
    stk[++top] = u;
    for (int tmp = 0; tmp < G[u].size(); tmp++) {
        int v = G[u][tmp];
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
                bcc_cnt++;
                int w;
                do {
                    w = stk[top--];
                    T[bcc_cnt + n].push_back(w);
                    T[w].push_back(bcc_cnt + n);
                } while (w != v);
                T[bcc_cnt + n].push_back(u);
                T[u].push_back(bcc_cnt + n);
            }
        } else {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

void dfs(int u, int father, int comp_id) {
    comp[u] = comp_id;
    depth[u] = depth[father] + 1;
    sum[u] = sum[father] + (u <= n ? 1 : 0);
    fa[u][0] = father;
    for (int i = 1; i <= LOG; i++) {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    for (int tmp = 0; tmp < T[u].size(); tmp++) {
        int v = T[u][tmp];
        if (v == father) continue;
        dfs(v, u, comp_id);
    }
}

int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    for (int i = LOG; i >= 0; i--) {
        if (depth[fa[u][i]] >= depth[v]) {
            u = fa[u][i];
        }
    }
    if (u == v) return u;
    for (int i = LOG; i >= 0; i--) {
        if (fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}

int main() {
    scanf("%d%d%d", &n, &m, &Q);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }

    idx = 0;
    top = 0;
    bcc_cnt = 0;
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) {
            tarjan(i);
            if (top > 0) {
                top--;
            }
        }
    }

    LOG = ceil(log2(n + bcc_cnt));
    for (int i = 1; i <= n; i++) {
        if (comp[i] == 0) {
            dfs(i, 0, i);
        }
    }

    while (Q--) {
        int S, T;
        scanf("%d%d", &S, &T);
        if (S == T) {
            printf("0\n");
        } else if (comp[S] != comp[T]) {
            printf("%d\n", n - 2);
        } else {
            int L = lca(S, T);
            int total = sum[S] + sum[T] - 2 * sum[L] + (L <= n ? 1 : 0);
            printf("%d\n", total - 2);
        }
    }

    return 0;
}

411val

#include "testlib.h"
#include <set>

int main(void) {
    using namespace std;
    registerValidation();
    int n, m, q;
    n = inf.readInt(1, 100000, "N");
    inf.readSpace();
    m = inf.readInt(1, 100000, "M");
    inf.readSpace();
    q = inf.readInt(1, 100000, "Q");
    inf.readEoln();
    set<pair<int, int> > visit;
    while(m--)
    {
        int u, v;
        u = inf.readInt(1, n, "u");
        v = inf.readInt(1, n, "v");
        ensuref(u != v, "u == v");
        if(u > v)
            swap(u, v);
        ensuref(visit.find(make_pair(u, v)) == visit.end(), "found {u, v}");
        visit.insert(make_pair(u, v)); 
        inf.readEoln();
    }
    while(q--)
    {
        int s, t;
        s = inf.readInt(1, n, "S");
        t = inf.readInt(1, n, "T");
        ensuref(s != t, "S == T");
        inf.readEoln();
    }
    inf.readEof();
    return 0;
}

411edtr

题目大意

给定一个无向图,多次询问,每次询问给出两个点 $S$ 和 $T$,求有多少个点 $v$($v \neq S$ 且 $v \neq T$)满足删除 $v$ 后 $S$ 和 $T$ 不再连通。

算法思路

本问题的核心在于找出图中所有能够断开 $S$ 和 $T$ 的连接的点,即 $S$ 和 $T$ 之间的必经点。为了解决这个问题,我们使用圆方树(Block-Cut Tree)来高效地识别这些必经点。

圆方树构建

  1. 点双连通分量(BCC)识别

    • 使用 Tarjan 算法识别图中的所有点双连通分量。
    • 每个点双连通分量对应圆方树中的一个方点,原图中的点对应圆点。
  2. 圆方树构建

    • 对于每个点双连通分量,创建一个方点,并将该方点与点双中的所有圆点连接。
    • 圆方树中的边连接方点和圆点,表示圆点属于对应的点双连通分量。

查询处理

  1. 连通性判断

    • 如果 $S$ 和 $T$ 不在同一个连通分量中,则删除任何点都无法使它们连通,因此答案为 $n-2$。
    • 如果 $S$ 和 $T$ 相同,则没有点可以删除,答案为 $0$。
  2. 必经点计算

    • 对于在同一个连通分量中的 $S$ 和 $T$,计算它们在圆方树路径上的圆点数量。
    • 使用最近公共祖先(LCA)技术快速计算路径上的圆点数量。
    • 答案即为路径上的圆点数量减去 $2$(排除 $S$ 和 $T$)。

算法正确性证明

圆方树的性质

  • 圆方树中的圆点代表原图中的节点,方点代表点双连通分量。
  • 在圆方树中,两个圆点之间的路径上的圆点就是原图中这两个点之间的所有必经点。
  • 这是因为点双连通分量内部存在多条路径,只有割点才是连接不同分量的关键点。

计算正确性

  • 对于查询 $S$ 和 $T$,如果它们不在同一个连通分量中,那么无论删除哪个点,它们仍然不连通,因此所有点(除 $S$ 和 $T$ 外)都满足条件。
  • 如果 $S$ 和 $T$ 在同一个连通分量中,那么只有路径上的圆点(必经点)才会影响它们的连通性。计算路径上的圆点数量并排除 $S$ 和 $T$,即可得到正确的答案。

复杂度分析

  • 时间复杂度

    • Tarjan 算法和圆方树构建的时间复杂度为 $O(n + m)$。
    • LCA 预处理和查询的时间复杂度为 $O(n \log n + q \log n)$。
    • 总体时间复杂度为 $O((n + m) + q \log n)$,适用于大规模数据。
  • 空间复杂度

    • 存储图和圆方树的空间复杂度为 $O(n + m)$。
    • LCA 预处理的空间复杂度为 $O(n \log n)$。

代码实现

#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;

const int MAXN = 1000000;
const int MAXT = 2 * MAXN;

int n, m, Q;
vector<int> G[MAXN + 5];
vector<int> T[MAXT + 5];
int dfn[MAXN + 5], low[MAXN + 5];
int stk[MAXN + 5], top;
int idx, bcc_cnt;
int comp[MAXT + 5];
int depth[MAXT + 5], sum[MAXT + 5];
int fa[MAXT + 5][21];
int LOG;

void tarjan(int u) {
    dfn[u] = low[u] = ++idx;
    stk[++top] = u;
    for (int v : G[u]) {
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
                bcc_cnt++;
                int w;
                do {
                    w = stk[top--];
                    T[bcc_cnt + n].push_back(w);
                    T[w].push_back(bcc_cnt + n);
                } while (w != v);
                T[bcc_cnt + n].push_back(u);
                T[u].push_back(bcc_cnt + n);
            }
        } else {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

void dfs(int u, int father, int comp_id) {
    comp[u] = comp_id;
    depth[u] = depth[father] + 1;
    sum[u] = sum[father] + (u <= n ? 1 : 0);
    fa[u][0] = father;
    for (int i = 1; i <= LOG; i++) {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    for (int v : T[u]) {
        if (v == father) continue;
        dfs(v, u, comp_id);
    }
}

int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    for (int i = LOG; i >= 0; i--) {
        if (depth[fa[u][i]] >= depth[v]) {
            u = fa[u][i];
        }
    }
    if (u == v) return u;
    for (int i = LOG; i >= 0; i--) {
        if (fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}

int main() {
    scanf("%d%d%d", &n, &m, &Q);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }

    idx = 0;
    top = 0;
    bcc_cnt = 0;
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) {
            tarjan(i);
        }
    }

    LOG = ceil(log2(n + bcc_cnt));
    for (int i = 1; i <= n; i++) {
        if (comp[i] == 0) {
            dfs(i, 0, i);
        }
    }

    while (Q--) {
        int S, T;
        scanf("%d%d", &S, &T);
        if (S == T) {
            printf("0\n");
        } else if (comp[S] != comp[T]) {
            printf("%d\n", n - 2);
        } else {
            int L = lca(S, T);
            int total = sum[S] + sum[T] - 2 * sum[L] + (L <= n ? 1 : 0);
            printf("%d\n", total - 2);
        }
    }

    return 0;
}

总结

本题解通过构建圆方树和利用 LCA 技术,高效地解决了图中必经点查询问题。算法正确性基于圆方树的性质,能够快速计算任意两点之间的必经点数量,适用于大规模数据输入。

小熊表情包

时间复杂度与本福特定律

https://www.luogu.com.cn/article/k8nh9vo0

看了漫士的这期视频,我忽然发现,std::sort 竟是 $\Theta(N \log N)$ 的,便马上做了个实验,Amazing啊,竟然有点符合本福特定律,以下是实验数据:

Avg_N = 5.06609e+06, Avg_time = 0.230004 s
P[1] = 0.229492
P[2] = 0.246826
P[3] = 0.234131
P[4] = 0.168091
P[5] = 0.0266113
P[6] = 0.0234375
P[7] = 0.0255127
P[8] = 0.0220947
P[9] = 0.0238037

也有可能是随机的数据有问题?希望知道的给一个答复。

代码(g++-14 main.cpp -o main -O2 -march=native):https://www.luogu.com.cn/paste/bilcktnw

main.cpp

#include <algorithm>
#include <ctime>
#include <iostream>
#include <numeric>
#include <random>

constexpr unsigned Tests = 8192;

clock_t run(unsigned n, unsigned* arr) {
    auto start = clock();
    std::sort(arr, arr + n);
    return clock() - start;
}

int main() {
    using namespace std;
    unsigned long cnt[10]{};
    double nsum = 0, tsum = 0;
    default_random_engine rnd(time(nullptr));
    uniform_int_distribution ndis(10000, 9999999);
    for (int i = 0; i < Tests; i++)
    {
        int n = ndis(rnd);
        nsum += n;
        cout << "Running Test " << i << ", N = " << n << "\n";
        auto arr = new unsigned[n];
        for (int j = 0; j < n; j++)
            arr[j] = rnd();
        auto res = run(n, arr);
        tsum += static_cast<double>(res) / CLOCKS_PER_SEC;
        while (res > 9)
            res /= 10;
        ++cnt[res];
        delete[] arr;
    }
    unsigned long tot = accumulate(cnt + 1, cnt + 10, 0ul);
    cout << "Avg_N = " << nsum / Tests << ", Avg_time = " << tsum / Tests << " s\n";
    for (int i = 1; i < 10; i++)
        cout << "P[" << i << "] = "
                << static_cast<double>(cnt[i]) / tot << endl;
    return 0;
}

小记录

P3384 【模板】重链剖分/树链剖分

题目描述

如题,已知一棵包含 $N$ 个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

  • 1 x y z,表示将树从 $x$ 到 $y$ 结点最短路径上所有节点的值都加上 $z$。

  • 2 x y,表示求树从 $x$ 到 $y$ 结点最短路径上所有节点的值之和。

  • 3 x z,表示将以 $x$ 为根节点的子树内所有节点值都加上 $z$。

  • 4 x,表示求以 $x$ 为根节点的子树内所有节点值之和。

输入格式

第一行包含 $4$ 个正整数 $N,M,R,P$,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含 $N$ 个非负整数,分别依次表示各个节点上初始的数值。

接下来 $N-1$ 行每行包含两个整数 $x,y$,表示点 $x$ 和点 $y$ 之间连有一条边(保证无环且连通)。

接下来 $M$ 行每行包含若干个正整数,每行表示一个操作。

输出格式

输出包含若干行,分别依次表示每个操作 $2$ 或操作 $4$ 所得的结果(对 $P$ 取模)。

输入输出样例 #1

输入 #1

5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3

输出 #1

2
21

说明/提示

【数据规模】

对于 $30\%$ 的数据: $1 \leq N \leq 10$,$1 \leq M \leq 10$;

对于 $70\%$ 的数据: $1 \leq N \leq {10}^3$,$1 \leq M \leq {10}^3$;

对于 $100\%$ 的数据: $1\le N \leq {10}^5$,$1\le M \leq {10}^5$,$1\le R\le N$,$1\le P \le 2^{30}$。所有输入的数均在 int 范围内。

【样例说明】

树的结构如下:

各个操作如下:

故输出应依次为 $2$ 和 $21$。

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define Rint register int
#define mem(a,b) memset(a,(b),sizeof(a))
#define Temp template<typename T>
using namespace std;
typedef long long LL;
Temp inline void read(T &x){
    x=0;T w=1,ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
    x=x*w;
}

#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)

const int maxn=200000+10;
int n,m,r,mod;
//见题意 
int e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
//链式前向星数组,w[]、wt[]初始点权数组 
int a[maxn<<2],laz[maxn<<2];
//线段树数组、lazy操作 
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn]; 
//son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点 
int res=0;
//查询答案 

inline void add(int x,int y){//链式前向星加边 
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
}
//-------------------------------------- 以下为线段树 
inline void pushdown(int rt,int lenn){
    laz[rt<<1]+=laz[rt];
    laz[rt<<1|1]+=laz[rt];
    a[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
    a[rt<<1|1]+=laz[rt]*(lenn>>1);
    a[rt<<1]%=mod;
    a[rt<<1|1]%=mod;
    laz[rt]=0;
}

inline void build(int rt,int l,int r){
    if(l==r){
        a[rt]=wt[l];
        if(a[rt]>mod)a[rt]%=mod;
        return;
    }
    build(lson);
    build(rson);
    a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}

inline void query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){res+=a[rt];res%=mod;return;}
    else{
        if(laz[rt])pushdown(rt,len);
        if(L<=mid)query(lson,L,R);
        if(R>mid)query(rson,L,R);
    }
}

inline void update(int rt,int l,int r,int L,int R,int k){
    if(L<=l&&r<=R){
        laz[rt]+=k;
        a[rt]+=k*len;
    }
    else{
        if(laz[rt])pushdown(rt,len);
        if(L<=mid)update(lson,L,R,k);
        if(R>mid)update(rson,L,R,k);
        a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
    }
}
//---------------------------------以上为线段树 
inline int qRange(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){//当两个点不在同一条链上 
        if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
        res=0;
        query(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
        ans+=res;
        ans%=mod;//按题意取模 
        x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
    }
    //直到两个点处于一条链上
    if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
    res=0;
    query(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
    ans+=res;
    return ans%mod;
}

inline void updRange(int x,int y,int k){//同上 
    k%=mod;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(1,1,n,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    update(1,1,n,id[x],id[y],k);
}

inline int qSon(int x){
    res=0;
    query(1,1,n,id[x],id[x]+siz[x]-1);//子树区间右端点为id[x]+siz[x]-1 
    return res;
}

inline void updSon(int x,int k){//同上 
    update(1,1,n,id[x],id[x]+siz[x]-1,k);
}

inline void dfs1(int x,int f,int deep){//x当前节点,f父亲,deep深度 
    dep[x]=deep;//标记每个点的深度 
    fa[x]=f;//标记每个点的父亲 
    siz[x]=1;//标记每个非叶子节点的子树大小 
    int maxson=-1;//记录重儿子的儿子数 
    for(Rint i=beg[x];i;i=nex[i]){
        int y=to[i];
        if(y==f)continue;//若为父亲则continue 
        dfs1(y,x,deep+1);//dfs其儿子 
        siz[x]+=siz[y];//把它的儿子数加到它身上 
        if(siz[y]>maxson)son[x]=y,maxson=siz[y];//标记每个非叶子节点的重儿子编号 
    }
}

inline void dfs2(int x,int topf){//x当前节点,topf当前链的最顶端的节点 
    id[x]=++cnt;//标记每个点的新编号 
    wt[cnt]=w[x];//把每个点的初始值赋到新编号上来 
    top[x]=topf;//这个点所在链的顶端 
    if(!son[x])return;//如果没有儿子则返回 
    dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理 
    for(Rint i=beg[x];i;i=nex[i]){
        int y=to[i];
        if(y==fa[x]||y==son[x])continue;
        dfs2(y,y);//对于每一个轻儿子都有一条从它自己开始的链 
    }
}

int main(){
    read(n);read(m);read(r);read(mod);
    for(Rint i=1;i<=n;i++)read(w[i]);
    for(Rint i=1;i<n;i++){
        int a,b;
        read(a);read(b);
        add(a,b);add(b,a);
    }
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n);
    while(m--){
        int k,x,y,z;
        read(k);
        if(k==1){
            read(x);read(y);read(z);
            updRange(x,y,z);
        }
        else if(k==2){
            read(x);read(y);
            printf("%d\n",qRange(x,y));
        }
        else if(k==3){
            read(x);read(y);
            updSon(x,y);
        }
        else{
            read(x);
            printf("%d\n",qSon(x));
        }
    }
}

P10814 【模板】离线二维数点

题目背景

青蛙。

题目描述

给你一个长为 $n$ 的序列 $a$,有 $m$ 次询问,每次询问给定 $l,r,x$,求 $[l,r]$ 区间中小于等于 $x$ 的元素个数。

输入格式

第一行两个数 $n,m$。

第二行 $n$ 个数表示序列 $a$。

之后 $m$ 行,每行三个数 $l,r,x$ 表示一次询问。

输出格式

对每个询问,输出一行一个数表示答案。

输入输出样例 #1

输入 #1

6 4
1 1 4 5 1 4
1 6 3
1 6 4
1 1 4
1 5 4

输出 #1

3
5
1
4

说明/提示

对于 $20\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 100$。

对于 $40\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 10^4$。

对于 $60\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 10^5$。

对于 $80\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 10^6$。

对于 $100\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 2\times10^6$。

#include<bits/stdc++.h>
using namespace std;
struct node{
    int x,id,val;
};
int lowbit(int i){
    return i&(-i);
}
int f[2000005];
void add(int x){
    for(int i=x;i<=2000000;i+=lowbit(i))f[i]++;
}
int ask(int x){
    int ans=0;
    for(int i=x;i>=1;i-=lowbit(i))ans+=f[i];
    return ans;
}
vector<node>vec[2000005];
int ans[2000005],n,m,a[2000006];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++){
        int l,r,x;
        cin>>l>>r>>x;
        vec[l-1].push_back({x,i,-1});
        vec[r].push_back({x,i,1});
    }
    for(int i=1;i<=n;i++){
        add(a[i]);
        for(int j=0;j<vec[i].size();j++){
            ans[vec[i][j].id]+=vec[i][j].val*ask(vec[i][j].x);
        }
    }
    for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
    return 0;
}

P5367 【模板】康托展开

题目描述

求 $1\sim N$ 的一个给定全排列在所有 $1\sim N$ 全排列中的排名。结果对 $998244353$ 取模。

输入格式

第一行一个正整数 $N$。

第二行 $N$ 个正整数,表示 $1\sim N$ 的一种全排列。

输出格式

一行一个非负整数,表示答案对 $998244353$ 取模的值。

输入输出样例 #1

输入 #1

3
2 1 3

输出 #1

3

输入输出样例 #2

输入 #2

4
1 2 4 3

输出 #2

2

说明/提示

对于 $10\%$ 数据,$1\le N\le 10$。

对于 $50\%$ 数据,$1\le N\le 5000$。

对于 $100\%$ 数据,$1\le N\le 1000000$。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;//上界
const int Mod=998244353;//神圣的模数
typedef long long ll;//加上这个很有用的,可以避免过多的重复long long
int n;
ll jc[maxn];//阶乘
ll tree[maxn];//树状数组
ll lowbit(ll x){return x&(-x);}//树状数组实现的支撑-取最低位,不知道的请翻到最后
ll sum(ll x)//求和
{
    ll ans=0;
    while(x!=0)
    {
        ans+=tree[x]%Mod;
        x-=lowbit(x);
    }
    return ans%Mod;
}
void add(ll x,ll k)//加法
{
    while(x<=n)
    {
        tree[x]+=k;
        x+=lowbit(x);
    }
}
int main()
{
    scanf("%d",&n);
    jc[0]=1;
    for(int i=1;i<=n;i++)//预处理阶乘
    {
        jc[i]=jc[i-1]*i%Mod;
        jc[i]%=Mod;
    }
    for(int i=1;i<=n;i++)
    {
        add(i,1);//如前面所说的那样,每一位都加上1
    }
    ll ans=1;//求排名,所以位置的值为1
    for(int i=1;i<=n;i++)
    {
        ll a;
        scanf("%lld",&a);//读入
        ans+=((sum(a)-1)*jc[n-i]%Mod)%Mod;//取模运算分进去,不知道的往后看
        add(a,-1);//这一个位置的值出现了,就把他减掉
    }
    printf("%lld\n",ans%Mod);
    return 0;
}

P3369 【模板】普通平衡树

题目描述

您需要动态地维护一个可重集合 $M$,并且提供以下操作:

  1. 向 $M$ 中插入一个数 $x$。
  2. 从 $M$ 中删除一个数 $x$(若有多个相同的数,应只删除一个)。
  3. 查询 $M$ 中有多少个数比 $x$ 小,并且将得到的答案加一。
  4. 查询如果将 $M$ 从小到大排列后,排名位于第 $x$ 位的数。
  5. 查询 $M$ 中 $x$ 的前驱(前驱定义为小于 $x$,且最大的数)。
  6. 查询 $M$ 中 $x$ 的后继(后继定义为大于 $x$,且最小的数)。

对于操作 3,5,6,不保证当前可重集中存在数 $x$。

输入格式

第一行为 $n$,表示操作的个数,下面 $n$ 行每行有两个数 $\text{opt}$ 和 $x$,$\text{opt}$ 表示操作的序号($ 1 \leq \text{opt} \leq 6 $)

输出格式

对于操作 $3,4,5,6$ 每行输出一个数,表示对应答案。

输入输出样例 #1

输入 #1

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

输出 #1

106465
84185
492737

说明/提示

【数据范围】
对于 $100\%$ 的数据,$1\le n \le 10^5$,$|x| \le 10^7$

来源:Tyvj1728 原名:普通平衡树

在此鸣谢

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
typedef long long LL;
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
//第一次打treap,不压行写注释XD
const int maxn = 1000019,INF = 1e9;
//平衡树,利用BST性质查询和修改,利用随机和堆优先级来保持平衡,把树的深度控制在log N,保证了操作效率
//基本平衡树有以下几个比较重要的函数:新建,插入,删除,旋转
//节点的基本属性有val(值),dat(随机出来的优先级)
//通过增加属性,结合BST的性质可以达到一些效果,如size(子树大小,查询排名),cnt(每个节点包含的副本数)等
int na;
int ch[maxn][2];//[i][0]代表i左儿子,[i][1]代表i右儿子
int val[maxn],dat[maxn];
int size[maxn],cnt[maxn];
int tot,root;
int New(int v){//新增节点,
    val[++tot] = v;//节点赋值
    dat[tot] = rand();//随机优先级
    size[tot] = 1;//目前是新建叶子节点,所以子树大小为1
    cnt[tot] = 1;//新建节点同理副本数为1
    return tot;
    }
void pushup(int id){//和线段树的pushup更新一样
    size[id] = size[ch[id][0]] + size[ch[id][1]] + cnt[id];//本节点子树大小 = 左儿子子树大小 + 右儿子子树大小 + 本节点副本数
    }
void build(){
    root = New(-INF),ch[root][1] = New(INF);//先加入正无穷和负无穷,便于之后操作(貌似不加也行)
    pushup(root);//因为INF > -INF,所以是右子树,
    }
void Rotate(int &id,int d){//id是引用传递,d(irection)为旋转方向,0为左旋,1为右旋
    int temp = ch[id][d ^ 1];//旋转理解:找个动图看一看就好(或参见其他OIer的blog)
    ch[id][d ^ 1] = ch[temp][d];//这里讲一个记忆技巧,这些数据都是被记录后马上修改
    ch[temp][d] = id;//所以像“Z”一样
    id = temp;//比如这个id,在上一行才被记录过,ch[temp][d]、ch[id][d ^ 1]也是一样的
    pushup(ch[id][d]),pushup(id);//旋转以后size会改变,看图就会发现只更新自己和转上来的点,pushup一下,注意先子节点再父节点
    }//旋转实质是({在满足BST的性质的基础上比较优先级}通过交换本节点和其某个叶子节点)把链叉开成二叉形状(从而控制深度),可以看图理解一下
void insert(int &id,int v){//id依然是引用,在新建节点时可以体现
    if(!id){
        id = New(v);//若节点为空,则新建一个节点
        return ;
        }
    if(v == val[id])cnt[id]++;//若节点已存在,则副本数++;
    else{//要满足BST性质,小于插到左边,大于插到右边
        int d = v < val[id] ? 0 : 1;//这个d是方向的意思,按照BST的性质,小于本节点则向左,大于向右
        insert(ch[id][d],v);//递归实现
        if(dat[id] < dat[ch[id][d]])Rotate(id,d ^ 1);//(参考一下图)与左节点交换右旋,与右节点交换左旋
        }
    pushup(id);//现在更新一下本节点的信息
    }
void Remove(int &id,int v){//最难de部分了
    if(!id)return ;//到这了发现查不到这个节点,该点不存在,直接返回
    if(v == val[id]){//检索到了这个值
        if(cnt[id] > 1){cnt[id]--,pushup(id);return ;}//若副本不止一个,减去一个就好
        if(ch[id][0] || ch[id][1]){//发现只有一个值,且有儿子节点,我们只能把值旋转到底部删除
            if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]]){//当前点被移走之后,会有一个新的点补上来(左儿子或右儿子),按照优先级,优先级大的补上来
                Rotate(id,1),Remove(ch[id][1],v);//我们会发现,右旋是与左儿子交换,当前点变成右节点;左旋则是与右儿子交换,当前点变为左节点
                }
            else Rotate(id,0),Remove(ch[id][0],v);
            pushup(id);
            }
        else id = 0;//发现本节点是叶子节点,直接删除
        return ;//这个return对应的是检索到值de所有情况
        }
    v < val[id] ? Remove(ch[id][0],v) : Remove(ch[id][1],v);//继续BST性质
    pushup(id);
    }
int get_rank(int id,int v){
    if(!id)return 1;//若查询值不存在,返回;因为最后要减一排除哨兵节点,想要结果为-1这里就返回0
    if(v == val[id])return size[ch[id][0]] + 1;//查询到该值,由BST性质可知:该点左边值都比该点的值(查询值)小,故rank为左儿子大小 + 1
    else if(v < val[id])return get_rank(ch[id][0],v);//发现需查询的点在该点左边,往左边递归查询
    else return size[ch[id][0]] + cnt[id] + get_rank(ch[id][1],v);//若查询值大于该点值。说明询问点在当前点的右侧,且此点的值都小于查询值,所以要加上cnt[id]
    }
int get_val(int id,int rank){
    if(!id)return INF;//一直向右找找不到,说明是正无穷
    if(rank <= size[ch[id][0]])return get_val(ch[id][0],rank);//左边排名已经大于rank了,说明rank对应的值在左儿子那里
        else if(rank <= size[ch[id][0]] + cnt[id])return val[id];//上一步排除了在左区间的情况,若是rank在左与中(目前节点)中,则直接返回目前节点(中区间)的值
    else return get_val(ch[id][1],rank - size[ch[id][0]] - cnt[id]);//剩下只能在右区间找了,rank减去左区间大小和中区间,继续递归
    }
int get_pre(int v){
    int id = root,pre;//递归不好返回,以循环求解
    while(id){//查到节点不存在为止
        if(val[id] < v)pre = val[id],id = ch[id][1];//满足当前节点比目标小,往当前节点的右侧寻找最优值
        else id = ch[id][0];//无论是比目标节点大还是等于目标节点,都不满足前驱条件,应往更小处靠近
        }
    return pre;
    }
int get_next(int v){
    int id = root,next;
    while(id){
        if(val[id] > v)next = val[id],id = ch[id][0];//同理,满足条件向左寻找更小解(也就是最优解)
        else id = ch[id][1];//与上方同理
        }
    return next;
    }
int main(){
    build();//不要忘记初始化[运行build()会连同root一并初始化,所以很重要]
    na = RD();
    for(int i = 1;i <= na;i++){
        int cmd = RD(),x = RD();
        if(cmd == 1)insert(root,x);//函数都写好了,注意:需要递归的函数都从根开始,不需要递归的函数直接查询
        else if(cmd == 2)Remove(root,x);
        else if(cmd == 3)printf("%d\n",get_rank(root,x) - 1);//注意:因为初始化时插入了INF和-INF,所以查询排名时要减1(-INF不是第一小,是“第零小”)
        else if(cmd == 4)printf("%d\n",get_val(root,x + 1));//同理,用排名查询值得时候要查x + 1名,因为第一名(其实不是)是-INF
        else if(cmd == 5)printf("%d\n",get_pre(x));
        else if(cmd == 6)printf("%d\n",get_next(x));
        }
    return 0;
    }

P3380 【模板】树套树

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

  1. 查询 $k$ 在区间内的排名;
  2. 查询区间内排名为 $k$ 的值;
  3. 修改某一位置上的数值;
  4. 查询 $k$ 在区间内的前驱(前驱定义为严格小于 $x$,且最大的数,若不存在输出 -2147483647);
  5. 查询 $k$ 在区间内的后继(后继定义为严格大于 $x$,且最小的数,若不存在输出 2147483647)。

对于一组元素,一个数的排名被定义为严格比它小的元素个数加一,而排名为 $k$ 的数被定义为“将元素从小到大排序后排在第 $k$ 位的元素值”。

输入格式

第一行两个数 $n,m$,表示长度为 $n$ 的有序序列和 $m$ 个操作。

第二行有 $n$ 个数,表示有序序列。

下面有 $m$ 行,$opt$ 表示操作标号。

若 $opt=1$,则为操作 $1$,之后有三个数 $l~r~k$,表示查询 $k$ 在区间 $[l,r]$ 的排名。

若 $opt=2$,则为操作 $2$,之后有三个数 $l~r~k$,表示查询区间 $[l,r]$ 内排名为 $k$ 的数。

若 $opt=3$,则为操作 $3$,之后有两个数 $pos~k$,表示将 $pos$ 位置的数修改为 $k$。

若 $opt=4$,则为操作 $4$,之后有三个数 $l~r~k$,表示查询区间 $[l,r]$ 内 $k$ 的前驱。

若 $opt=5$,则为操作 $5$,之后有三个数 $l~r~k$,表示查询区间 $[l,r]$ 内 $k$ 的后继。

输出格式

对于操作 $1,2,4,5$,各输出一行,表示查询结果。

输入输出样例 #1

输入 #1

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

输出 #1

2
4
3
4
9

说明/提示

$1\le n,m\le5\times 10^4$,序列中的值在任何时刻 $\in[0,10^8]$。

题目来源:bzoj3196 / Tyvj1730,在此鸣谢。

此数据为洛谷原创。(特别提醒:此数据不保证操作 4、5 一定存在,故请务必考虑不存在的情况。)

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;const int N=5*1e4+10;const int M=1e5+10;
const int B=260;const int B2=300;int a[N];//维护的表格 
int cnt1[N/B+3][M/B2+3];int cnt2[N/B+3][M];int n;int m;int bi[N];int bi1[M];
int tr1[M];int tr2[M];map <int,int> mp;int S;int Pr[M];int Pl[M];int val[M];
inline int frk(int l,int r,int va)//查询元素的排名 
{
    int p1=bi[l];int p2=bi[r];int ret=0;
    if(p1==p2){for(int i=l;i<=r;i++)ret+=(a[i]<va);return ret+1;}
    for(int i=l;bi[i]==p1;i++)ret+=(a[i]<va);
    for(int i=r;bi[i]==p2;i--)ret+=(a[i]<va);p2--;
    for(int i=1;i<bi1[va];i++)ret+=cnt1[p2][i];
    for(int i=1;i<bi1[va];i++)ret-=cnt1[p1][i];
    for(int i=va-1;bi1[i]==bi1[va];i--)ret+=cnt2[p2][i];
    for(int i=va-1;bi1[i]==bi1[va];i--)ret-=cnt2[p1][i];return ret+1;
}
inline int ckth(const int& p1,const int& p2,int k)//辅助函数,查询kth 
{
    int ret=B2;int cur=0;
    for(int t=1;cur<k;ret+=B2,t++)cur+=cnt1[p2][t]-cnt1[p1][t]+tr1[t];ret-=B2;
    for(;cur>=k;ret--)cur-=cnt2[p2][ret]-cnt2[p1][ret]+tr2[ret];return ret+1;
}
inline int cpre(const int& p1,const int& p2,int k)//辅助函数,查询前驱 
{
    for(int i=k-1;bi1[i]==bi1[k];i--)
        if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
    int p;for(p=bi1[k]-1;(cnt1[p2][p]-cnt1[p1][p]+tr1[p])==0;p--);
    for(int i=Pr[p];;i--)if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
}
inline int csuf(const int& p1,const int& p2,int k)//辅助函数,查询后继 
{
    for(int i=k+1;bi1[i]==bi1[k];i++)
        if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
    int p;for(p=bi1[k]+1;(cnt1[p2][p]-cnt1[p1][p]+tr1[p])==0;p++);
    for(int i=Pl[p];;i++)if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
}
# define ins(x) tr1[bi1[x]]++,tr2[x]++
# define del(x) tr1[bi1[x]]--,tr2[x]--
inline int calc(int l,int r,int k,int(*f)(const int& p1,const int& p2,int k))//这里用了个函数指针 
{
    int p1=bi[l];int p2=bi[r];int ret=0;//直接处理出区间的cnt1,cnt2数组 
    if(p1==p2)
    {
        for(int i=l;i<=r;i++)ins(a[i]);ret=f(p1,p2,k);
        for(int i=l;i<=r;i++)del(a[i]);return val[ret];
    }
    for(int i=l;bi[i]==p1;i++)ins(a[i]);
    for(int i=r;bi[i]==p2;i--)ins(a[i]);ret=f(p1,p2-1,k);
    for(int i=l;bi[i]==p1;i++)del(a[i]);
    for(int i=r;bi[i]==p2;i--)del(a[i]);return val[ret];//记得还原回离散化之前的值 
}
inline void modify(int pos,int y)//暴力修改 
{
    int p=bi1[a[pos]];for(int i=bi[pos];i<=bi[n];i++)cnt1[i][p]--;
    p=a[pos];for(int i=bi[pos];i<=bi[n];i++)cnt2[i][p]--;
    p=bi1[y];for(int i=bi[pos];i<=bi[n];i++)cnt1[i][p]++;
    for(int i=bi[pos];i<=bi[n];i++)cnt2[i][y]++;a[pos]=y;
}
struct opt{int tp;int l;int r;int k;}op[N];
int main()
{
    scanf("%d%d",&n,&m);mp[-2147483647]=1;mp[2147483647]=1;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),mp[a[i]]=1;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&op[i].tp);
        if(op[i].tp!=3)scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);
        else scanf("%d%d",&op[i].l,&op[i].k);if(op[i].tp!=2)mp[op[i].k]=1;    
    }
    S=mp.size();map <int,int> :: iterator it,it1;//离散化 
    for(it=mp.begin(),it1=it,++it1;it1!=mp.end();++it,++it1)it1->second+=it->second;
    for(it=mp.begin();it!=mp.end();++it)val[it->second]=it->first;
    for(int i=1;i<=n;i++)a[i]=mp[a[i]];
    for(int i=1;i<=m;i++)if(op[i].tp!=2)op[i].k=mp[op[i].k];
    for(int i=1;i<=n;i++)bi[i]=(i-1)/B+1;for(int i=1;i<=S;i++)bi1[i]=(i-1)/B2+1;
    for(int i=1;i<=S;i++)Pr[bi1[i]]=i;for(int i=S;i>=1;i--)Pl[bi1[i]]=i;
    for(int i=1;i<=n;i++)
    {
        int p=bi1[a[i]];for(int j=bi[i];j<=bi[n];j++)cnt1[j][p]++;
        p=a[i];for(int j=bi[i];j<=bi[n];j++)cnt2[j][p]++;
    }ins(1);ins(S);//插入哨兵 
    for(int i=1;i<=m;i++)
        switch(op[i].tp)
        {
            case 1:{printf("%d\n",frk(op[i].l,op[i].r,op[i].k));break;}
            case 2:{printf("%d\n",calc(op[i].l,op[i].r,op[i].k+1,ckth));break;}
            case 3:{modify(op[i].l,op[i].k);break;}
            case 4:{printf("%d\n",calc(op[i].l,op[i].r,op[i].k,cpre));break;}
            case 5:{printf("%d\n",calc(op[i].l,op[i].r,op[i].k,csuf));break;}
        }return 0;//拜拜程序~ 
}

P3373 【模板】线段树 2

题目描述

如题,已知一个数列 $a$,你需要进行下面三种操作:

  • 将某区间每一个数乘上 $x$;
  • 将某区间每一个数加上 $x$;
  • 求出某区间每一个数的和。

输入格式

第一行包含三个整数 $n,q,m$,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 $n$ 个用空格分隔的整数,其中第 $i$ 个数字表示数列第 $i$ 项的初始值 $a_i$。

接下来 $q$ 行每行包含若干个整数,表示一个操作,具体如下:

操作 $1$: 格式:1 x y k 含义:将区间 $[x,y]$ 内每个数乘上 $k$。

操作 $2$: 格式:2 x y k 含义:将区间 $[x,y]$ 内每个数加上 $k$。

操作 $3$: 格式:3 x y 含义:输出区间 $[x,y]$ 内每个数的和对 $m$ 取模所得的结果。

输出格式

输出包含若干行整数,即为所有操作 $3$ 的结果。

输入输出样例 #1

输入 #1

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

输出 #1

17
2

说明/提示

【数据范围】

对于 $30\%$ 的数据:$n \le 8$,$q \le 10$。
对于 $70\%$ 的数据:$n \le 10^3 $,$q \le 10^4$。
对于 $100\%$ 的数据:$1 \le n \le 10^5$,$1 \le q \le 10^5,1\le a_i,k\le 10^4$。

除样例外,$m = 571373$。

(数据已经过加强 ^_^)

样例说明:

故输出应为 $17$、$2$($40 \bmod 38 = 2$)。

#include <bits/stdc++.h>

#define MAXN 100010
#define ll long long

using namespace std;

int n, m, mod;
int a[MAXN];

struct Segment_Tree {
    ll sum, add, mul;
    int l, r;
}s[MAXN * 4];

void update(int pos) {
    s[pos].sum = (s[pos << 1].sum + s[pos << 1 | 1].sum) % mod;
    return;
}

void pushdown(int pos) { //pushdown的维护
    s[pos << 1].sum = (s[pos << 1].sum * s[pos].mul + s[pos].add * (s[pos << 1].r - s[pos << 1].l + 1)) % mod;
    s[pos << 1 | 1].sum = (s[pos << 1 | 1].sum * s[pos].mul + s[pos].add * (s[pos << 1 | 1].r - s[pos << 1 | 1].l + 1)) % mod;

    s[pos << 1].mul = (s[pos << 1].mul * s[pos].mul) % mod;
    s[pos << 1 | 1].mul = (s[pos << 1 | 1].mul * s[pos].mul) % mod;

    s[pos << 1].add = (s[pos << 1].add * s[pos].mul + s[pos].add) % mod;
    s[pos << 1 | 1].add = (s[pos << 1 | 1].add * s[pos].mul + s[pos].add) % mod;

    s[pos].add = 0;
    s[pos].mul = 1;
    return; 
}

void build_tree(int pos, int l, int r) { //建树
    s[pos].l = l;
    s[pos].r = r;
    s[pos].mul = 1;

    if (l == r) {
        s[pos].sum = a[l] % mod;
        return;
    }

    int mid = (l + r) >> 1;
    build_tree(pos << 1, l, mid);
    build_tree(pos << 1 | 1, mid + 1, r);
    update(pos);
    return;
}

void ChangeMul(int pos, int x, int y, int k) { //区间乘法
    if (x <= s[pos].l && s[pos].r <= y) {
        s[pos].add = (s[pos].add * k) % mod;
        s[pos].mul = (s[pos].mul * k) % mod;
        s[pos].sum = (s[pos].sum * k) % mod;
        return;
    }

    pushdown(pos);
    int mid = (s[pos].l + s[pos].r) >> 1;
    if (x <= mid) ChangeMul(pos << 1, x, y, k);
    if (y > mid) ChangeMul(pos << 1 | 1, x, y, k);
    update(pos);
    return;
}

void ChangeAdd(int pos, int x, int y, int k) { //区间加法
    if (x <= s[pos].l && s[pos].r <= y) {
        s[pos].add = (s[pos].add + k) % mod;
        s[pos].sum = (s[pos].sum + k * (s[pos].r - s[pos].l + 1)) % mod;
        return;
    }

    pushdown(pos);
    int mid = (s[pos].l + s[pos].r) >> 1;
    if (x <= mid) ChangeAdd(pos << 1, x, y, k);
    if (y > mid) ChangeAdd(pos << 1 | 1, x, y, k);
    update(pos);
    return;
}

ll AskRange(int pos, int x, int y) { //区间询问
    if (x <= s[pos].l && s[pos].r <= y) {
        return s[pos].sum;
    }

    pushdown(pos);
    ll val = 0;
    int mid = (s[pos].l + s[pos].r) >> 1;
    if (x <= mid) val = (val + AskRange(pos << 1, x, y)) % mod;
    if (y > mid) val = (val + AskRange(pos << 1 | 1, x, y)) % mod;
    return val;
}

int main() {
    scanf("%d%d%d", &n, &m, &mod);

    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }

    build_tree(1, 1, n);

    for (int i = 1; i <= m; i++) {
        int opt, x, y;
        scanf("%d%d%d", &opt, &x, &y);
        if (opt == 1) {
            int k;
            scanf("%d", &k);
            ChangeMul(1, x, y, k);
        }
        if (opt == 2) {
            int k;
            scanf("%d", &k);
            ChangeAdd(1, x, y, k);
        }
        if (opt == 3) {
            printf("%lld\n", AskRange(1, x, y));
        }
    }

    return 0;
}

P6242 【模板】线段树 3(区间最值操作、区间历史最值)

题目背景

本题是线段树维护区间最值操作与区间历史最值的模板。

题目描述

给出一个长度为 $n$ 的数列 $A$,同时定义一个辅助数组 $B$,$B$ 开始与 $A$ 完全相同。接下来进行了 $m$ 次操作,操作有五种类型,按以下格式给出:

  • 1 l r k:对于所有的 $i\in[l,r]$,将 $A_i$ 加上 $k$($k$ 可以为负数)。
  • 2 l r v:对于所有的 $i\in[l,r]$,将 $A_i$ 变成 $\min(A_i,v)$。
  • 3 l r:求 $\sum_{i=l}^{r}A_i$。
  • 4 l r:对于所有的 $i\in[l,r]$,求 $A_i$ 的最大值。
  • 5 l r:对于所有的 $i\in[l,r]$,求 $B_i$ 的最大值。

在每一次操作后,我们都进行一次更新,让 $B_i\gets\max(B_i,A_i)$。

输入格式

第一行包含两个正整数 $n,m$,分别表示数列 $A$ 的长度和操作次数。

第二行包含 $n$ 个整数 $A_1,A_2,\cdots,A_n$,表示数列 $A$。

接下来 $m$ 行,每行行首有一个整数 $op$,表示操作类型;接下来两个或三个整数表示操作参数,格式见【题目描述】。

输出格式

对于 $op\in\{3,4,5\}$ 的操作,输出一行包含一个整数,表示这个询问的答案。

输入输出样例 #1

输入 #1

5 6
1 2 3 4 5
3 2 5
1 1 3 3
4 2 4
2 3 4 1
5 1 5
3 1 4

输出 #1

14
6
6
11

说明/提示

样例说明 #1

操作次数 输入内容 操作 数列 输出结果
0 $1,2,3,4,5$
1 3 2 5 求出 $[2,5]$ 所有数的和 $1,2,3,4,5$ 14
2 1 1 3 3 将 $[1,3]$ 内所有数加 $3$ $4,5,6,4,5$
3 4 2 4 求出 $[2,4]$ 所有数的最大值 $4,5,6,4,5$ 6
4 2 3 4 1 将 $[3,4]$ 所有数与 $1$ 取最小值 $4,5,1,1,5$
5 5 1 5 求出 $[1,5]$ 所有位置历史最大值的最大值 $4,5,1,1,5$ 6
6 3 1 4 求出 $[1,4]$ 所有数的和 $4,5,1,1,5$ 11

数据规模与约定

  • 对于测试点 $1,2$,满足 $n,m\leq 5000$;
  • 对于测试点 $3,4$,满足 $op\in\{1,2,3,4\}$;
  • 对于测试点 $5,6$,满足 $op\in\{1,3,4,5\}$;
  • 对于全部测试数据,保证 $1\leq n,m\leq 5\times 10^5$,$-5\times10^8\leq A_i\leq 5\times10^8$,$op\in[1,5]$,$1 \leq l\leq r \leq n$,$-2000\leq k\leq 2000$,$-5\times10^8\leq v\leq 5\times10^8$。

提示

本题输入量较大,请使用合理高效的读入方法。

/*
this code is made by warzone
2022.2.14 21:25
*/
#include<stdio.h>
#include<string.h>
typedef long long ll;
typedef unsigned int word;
struct READ{//快读
    char pool[5<<22],*top,w;
    inline READ(){fread(top=pool,5<<22,1,stdin);}
    template<typename type>
    inline READ& operator >>(type& num){
        for(w=1;'0'>*top||*top>'9';)
            w=*(top++)=='-'? -1:1;
        for(num=0;'0'<=*top&&*top<='9';)
            num=num*10+(*(top++)-'0');
        return num*=w,*this;
    }
}cin;
const int inf=0x80000000;//−∞
inline int max(const int a,const int b){
    return a>b? a:b;}
/* 向量/矩阵
⎡a⎤   ⎡a −∞⎤
⎣b⎦   ⎣b  0⎦
*/
struct matrix{
    int a,b;
    inline matrix(){}
    inline matrix(const matrix &p)=default;
    inline matrix(int A,int B):a(A),b(B){}
    inline matrix operator+(const matrix &p)const{//矩阵/向量 加法
        return matrix(max(a,p.a),max(b,p.b));}
    inline matrix operator()(const matrix &p)const{//矩阵乘法
        return matrix(a==inf||p.a==inf? inf:a+p.a,
            b==inf||p.a==inf? p.b:max(b+p.a,p.b));}
    inline bool operator!=(const matrix &p)const{
        return a!=p.a||b!=p.b;}
}const I(0,inf),vec0(inf,inf);
word n,m;
struct segment_tree{//线段树(zkw)
    ll sum[1u<<20];
    int cnt[1u<<20];
    matrix mx[1u<<20],M[1u<<20];
    matrix se[1u<<20],E[1u<<20];
    inline segment_tree(){
        for(word i=0;i<(1u<<20);++i) M[i]=E[i]=I;
        se[1u<<19]=vec0,cnt[1u<<19]=1,cin>>n>>m;
        for(int i=(1u<<19)+1,num;i<=(1u<<19|n);++i){
            se[i]=vec0,cnt[i]=1,cin>>num;
            sum[i]=mx[i].a=mx[i].b=num;
        }
        for(word i=(1u<<19|n)+1;i<(1u<<20);++i)
            se[i]=vec0,cnt[i]=1;
        for(word i=(1u<<19)-1;i;--i) pushup(i);
    }
    #define l (rt<<1)
    #define r (rt<<1|1)
    inline void pushup(const word rt){//上传信息
        sum[rt]=sum[l]+sum[r];
        if(mx[l].a>mx[r].a){
            mx[rt]=mx[l],cnt[rt]=cnt[l];
            se[rt]=se[l]+se[r]+mx[r];
        }else if(mx[l].a<mx[r].a){
            mx[rt]=mx[r],cnt[rt]=cnt[r];
            se[rt]=se[l]+se[r]+mx[l];
        }else{
            mx[rt]=mx[l]+mx[r];
            cnt[rt]=cnt[l]+cnt[r];
            se[rt]=se[l]+se[r];
        }
    }
    inline void Mmul(const matrix &p,const word id){//修改 mx
        mx[id]=p(mx[id]),M[id]=p(M[id]),sum[id]+=1ll*cnt[id]*p.a;}
    inline void Emul(const matrix &p,const word id,const word size){//修改 se
        se[id]=p(se[id]),E[id]=p(E[id]);
        sum[id]+=1ll*(size-cnt[id])*p.a;
    }
    inline void pushdown(const word rt,const word size){//下传标记
        Mmul(mx[l].a==mx[rt].a-M[rt].a? M[rt]:E[rt],l);
        Mmul(mx[r].a==mx[rt].a-M[rt].a? M[rt]:E[rt],r);
        //注意此处不能用 mx[l].a 和 mx[r].a 的大小关系来判断划分,因为标记下传后 mx 会被修改
        if(size!=1) Emul(E[rt],l,size),Emul(E[rt],r,size);
        M[rt]=E[rt]=I;
    }
    inline void plus(const word f,const word t,const int k,
        const word rt=1,const word size=1u<<18){//区间加
        if(size==0||(f==0&&t==(size<<1)-1))
            return Mmul(matrix(k,k),rt),Emul(matrix(k,k),rt,size? size<<1:1);
        auto lf=[&](word f,word t){plus(f,t,k,l,size>>1);};
        auto rf=[&](word f,word t){plus(f,t,k,r,size>>1);};
        pushdown(rt,size);
        if(f&size) rf(f&~size,t&~size);
        else if((t&size)^size) lf(f,t);
        else lf(f,size-1),rf(0,t&~size);
        pushup(rt);
    }
    inline void min(const word f,const word t,const int k,
        const word rt=1,const word size=1u<<18){//区间取 min
        if(k>=mx[rt].a) return;
        const auto lf=[&](word f,word t){min(f,t,k,l,size>>1);};
        const auto rf=[&](word f,word t){min(f,t,k,r,size>>1);};
        if(size==0||(f==0&&t==(size<<1)-1)){
            if(k>se[rt].a) return Mmul(matrix(k-mx[rt].a,k-mx[rt].a),rt);
            return pushdown(rt,size),lf(0,size-1),rf(0,size-1),pushup(rt);
        }
        pushdown(rt,size);
        if(f&size) rf(f&~size,t&~size);
        else if((t&size)^size) lf(f,t);
        else lf(f,size-1),rf(0,t&~size);
        pushup(rt);
    }
    inline ll getsum(const word f,const word t,
        const word rt=1,const word size=1u<<18){//区间求和
        if(size==0||(f==0&&t==(size<<1)-1)) return sum[rt];
        const auto lf=[&](word f,word t)->ll{return getsum(f,t,l,size>>1);};
        const auto rf=[&](word f,word t)->ll{return getsum(f,t,r,size>>1);};
        pushdown(rt,size);
        if(f&size) return rf(f&~size,t&~size);
        else if((t&size)^size) return lf(f,t);
        return lf(f,size-1)+rf(0,t&~size);
    }
    inline int geta(const word f,const word t,
        const word rt=1,const word size=1u<<18){//区间最值
        if(size==0||(f==0&&t==(size<<1)-1)) return mx[rt].a;
        const auto lf=[&](word f,word t)->ll{return geta(f,t,l,size>>1);};
        const auto rf=[&](word f,word t)->ll{return geta(f,t,r,size>>1);};
        pushdown(rt,size);
        if(f&size) return rf(f&~size,t&~size);
        else if((t&size)^size) return lf(f,t);
        return max(lf(f,size-1),rf(0,t&~size));
    }
    inline int getb(const word f,const word t,
        const word rt=1,const word size=1u<<18){//区间历史最值
        if(size==0||(f==0&&t==(size<<1)-1)) return max(mx[rt].b,se[rt].b);
        const auto lf=[&](word f,word t)->ll{return getb(f,t,l,size>>1);};
        const auto rf=[&](word f,word t)->ll{return getb(f,t,r,size>>1);};
        pushdown(rt,size);
        if(f&size) return rf(f&~size,t&~size);
        else if((t&size)^size) return lf(f,t);
        return max(lf(f,size-1),rf(0,t&~size));
    }
    #undef l
    #undef r
}tree;
int main(){
    for(int opt,l,r;m;--m)
        if(cin>>opt>>l>>r,opt==1)
            cin>>opt,tree.plus(l,r,opt);
        else if(opt==2) cin>>opt,tree.min(l,r,opt);
        else if(opt==4) printf("%d\n",tree.geta(l,r));
        else if(opt==5) printf("%d\n",tree.getb(l,r));
        else printf("%lld\n",tree.getsum(l,r));
    return 0;
}
标准库头文件 <algorithm>

 C++ 标准库头文件 
此头文件是算法库的一部分。

包含
<initializer_list>

(C++11)

std::initializer_list 类模板
类
定义于命名空间 std::ranges
返回类型 (C++20)
ranges::in_fun_result

(C++20)

提供了一种将迭代器和函数对象存储为单个单元的方法
(类模板)
ranges::in_in_result

(C++20)

提供了一种将两个迭代器存储为单个单元的方法
(类模板)
ranges::in_out_result

(C++20)

提供了一种将两个迭代器存储为单个单元的方法
(类模板)
ranges::in_in_out_result

(C++20)

提供了一种将三个迭代器存储为单个单元的方法
(类模板)
ranges::in_out_out_result

(C++20)

提供了一种将三个迭代器存储为单个单元的方法
(类模板)
ranges::min_max_result

(C++20)

提供了一种将两个相同类型的对象或引用存储为单个单元的方法
(类模板)
ranges::in_found_result

(C++20)

提供了一种将迭代器和布尔标志存储为单个单元的方法
(类模板)
ranges::in_value_result

(C++23)

提供了一种将迭代器和值存储为单个单元的方法
(类模板)
ranges::out_value_result

(C++23)

提供了一种将迭代器和值存储为单个单元的方法
(类模板)
函数
非修改序列操作
all_of
any_of
none_of

(C++11)
(C++11)
(C++11)

检查谓词对于范围中所有、任何或没有元素是否为真
(函数模板)
for_each

将一元函数对象应用于来自范围的元素
(函数模板)
for_each_n

(C++17)

将函数对象应用于序列的前 N 个元素
(函数模板)
count
count_if

返回满足特定条件的元素数量
(函数模板)
mismatch

查找两个范围不同的第一个位置
(函数模板)
find
find_if
find_if_not

(C++11)

查找满足特定条件的第一个元素
(函数模板)
find_end

查找某个范围中元素的最后一个序列
(函数模板)
find_first_of

搜索元素集合中的任何一个
(函数模板)
adjacent_find

查找第一个相等的相邻项(或满足给定谓词的相邻项)
(函数模板)
search

搜索元素范围的第一次出现
(函数模板)
search_n

搜索范围中连续重复元素一定次数的第一次出现
(函数模板)
修改序列操作
copy
copy_if

(C++11)

将元素范围复制到新位置
(函数模板)
copy_n

(C++11)

将一定数量的元素复制到新位置
(函数模板)
copy_backward

以向后顺序复制元素范围
(函数模板)
move

(C++11)

将元素范围移动到新位置
(函数模板)
move_backward

(C++11)

以向后顺序将元素范围移动到新位置
(函数模板)
fill

将给定值复制赋值给范围中的每个元素
(函数模板)
fill_n

将给定值复制赋值给范围中的 N 个元素
(函数模板)
transform

将函数应用于元素范围,并将结果存储在目标范围中
(函数模板)
generate

将连续函数调用的结果赋值给范围中的每个元素
(函数模板)
generate_n

将连续函数调用的结果赋值给范围中的 N 个元素
(函数模板)
remove
remove_if

移除满足特定条件的元素
(函数模板)
remove_copy
remove_copy_if

复制元素范围,省略那些满足特定条件的元素
(函数模板)
replace
replace_if

将所有满足特定条件的值替换为另一个值
(函数模板)
replace_copy
replace_copy_if

复制一个范围,将满足特定条件的元素替换为另一个值
(函数模板)
swap

交换两个对象的值
(函数模板)
swap_ranges

交换两个元素范围
(函数模板)
iter_swap

交换两个迭代器指向的元素
(函数模板)
reverse

反转范围中元素的顺序
(函数模板)
reverse_copy

创建一个反转的范围副本
(函数模板)
rotate

旋转范围中元素的顺序
(函数模板)
rotate_copy

复制并旋转元素范围
(函数模板)
shift_left
shift_right

(C++20)

移动范围中的元素
(函数模板)
random_shuffle
shuffle

(until C++17)
(C++11)

随机重新排序范围中的元素
(函数模板)
sample

(C++17)

从序列中选择 N 个随机元素
(函数模板)
unique

移除范围中连续重复的元素
(函数模板)
unique_copy

创建某个元素范围的副本,其中不包含连续重复项
(函数模板)
分区操作
is_partitioned

(C++11)

确定范围是否由给定谓词分区
(函数模板)
partition

将元素范围划分为两组
(函数模板)
partition_copy

(C++11)

复制一个范围,将元素划分为两组
(函数模板)
stable_partition

将元素划分为两组,同时保持其相对顺序
(函数模板)
partition_point

(C++11)

定位已分区范围的分区点
(函数模板)
排序操作
is_sorted

(C++11)

检查范围是否已排序为升序
(函数模板)
is_sorted_until

(C++11)

查找最大的已排序子范围
(函数模板)
sort

将范围排序为升序
(函数模板)
partial_sort

对范围的前 N 个元素进行排序
(函数模板)
partial_sort_copy

复制并部分排序元素范围
(函数模板)
stable_sort

排序元素范围,同时保持相等元素之间的顺序
(函数模板)
nth_element

部分排序给定范围,确保它按给定元素分区
(函数模板)
二分搜索操作 (在已排序范围上)
lower_bound

返回指向第一个不小于给定值的元素的迭代器
(function template)
upper_bound

返回指向首个大于某值的元素的迭代器
(function template)
binary_search

确定元素是否存在于部分有序的范围内
(function template)
equal_range

返回与特定键匹配的元素范围
(function template)
其他排序范围上的操作
merge

合并两个已排序的范围
(function template)
inplace_merge

就地合并两个有序范围
(function template)
集合操作(在已排序的范围上)
includes

如果一个序列是另一个序列的子序列,则返回 true
(function template)
set_difference

计算两个集合的差集
(function template)
set_intersection

计算两个集合的交集
(function template)
set_symmetric_difference

计算两个集合的对称差集
(function template)
set_union

计算两个集合的并集
(function template)
堆操作
is_heap

(C++11)

检查给定范围是否为最大堆
(function template)
is_heap_until

(C++11)

查找作为最大堆的最大子范围
(function template)
make_heap

从元素范围创建最大堆
(function template)
push_heap

向最大堆添加元素
(function template)
pop_heap

从最大堆中移除最大的元素
(function template)
sort_heap

将最大堆转换为升序排序的元素范围
(function template)
最小值/最大值操作
max

返回给定值中较大的那个
(function template)
max_element

返回范围中最大的元素
(function template)
min

返回给定值中较小的那个
(function template)
min_element

返回范围中最小的元素
(function template)
minmax

(C++11)

返回两个元素中较小和较大的那个
(function template)
minmax_element

(C++11)

返回范围中最小和最大的元素
(function template)
clamp

(C++17)

将值限制在边界值对之间
(function template)
比较操作
equal

确定两组元素是否相同
(function template)
lexicographical_compare

如果一个范围在字典序上小于另一个范围,则返回 true
(function template)
lexicographical_compare_three_way

(C++20)

使用三路比较比较两个范围
(function template)
排列操作
is_permutation

(C++11)

确定一个序列是否是另一个序列的排列
(function template)
next_permutation

生成元素范围的下一个更大的字典序排列
(function template)
prev_permutation

生成元素范围的下一个更小的字典序排列
(function template)
类似函数的实体 (C++20)
定义于命名空间 std::ranges
非修改序列操作
ranges::all_of
ranges::any_of
ranges::none_of

(C++20)
(C++20)
(C++20)

检查谓词对于范围中所有、任何或没有元素是否为真
(algorithm function object)
ranges::for_each

(C++20)

将一元函数对象应用于来自范围的元素
(algorithm function object)
ranges::for_each_n

(C++20)

将函数对象应用于序列的前 N 个元素
(algorithm function object)
ranges::count
ranges::count_if

(C++20)
(C++20)

返回满足特定条件的元素数量
(algorithm function object)
ranges::mismatch

(C++20)

查找两个范围不同的第一个位置
(algorithm function object)
ranges::find
ranges::find_if
ranges::find_if_not

(C++20)
(C++20)
(C++20)

查找满足特定条件的第一个元素
(algorithm function object)
ranges::find_last
ranges::find_last_if
ranges::find_last_if_not

(C++23)
(C++23)
(C++23)

查找满足特定条件的最后一个元素
(algorithm function object)
ranges::find_end

(C++20)

查找某个范围中元素的最后一个序列
(algorithm function object)
ranges::find_first_of

(C++20)

搜索元素集合中的任何一个
(algorithm function object)
ranges::adjacent_find

(C++20)

查找第一个相等的相邻项(或满足给定谓词的相邻项)
(algorithm function object)
ranges::search

(C++20)

搜索元素范围的第一次出现
(algorithm function object)
ranges::search_n

(C++20)

搜索范围中连续重复元素一定次数的第一次出现
(algorithm function object)
ranges::contains
ranges::contains_subrange

(C++23)
(C++23)

检查范围是否包含给定的元素或子范围
(algorithm function object)
ranges::starts_with

(C++23)

检查一个范围是否以另一个范围开始
(algorithm function object)
ranges::ends_with

(C++23)

检查一个范围是否以另一个范围结束
(algorithm function object)
折叠操作
ranges::fold_left

(C++23)

左折叠元素范围
(algorithm function object)
ranges::fold_left_first

(C++23)

使用第一个元素作为初始值左折叠元素范围
(algorithm function object)
ranges::fold_right

(C++23)

右折叠元素范围
(algorithm function object)
ranges::fold_right_last

(C++23)

使用最后一个元素作为初始值右折叠元素范围
(algorithm function object)
ranges::fold_left_with_iter

(C++23)

左折叠元素范围,并返回一个 pair (迭代器, 值)
(algorithm function object)
ranges::fold_left_first_with_iter

(C++23)

使用第一个元素作为初始值左折叠元素范围,并返回一个 pair (迭代器, optional)
(algorithm function object)
修改序列操作
ranges::copy
ranges::copy_if

(C++20)
(C++20)

将元素范围复制到新位置
(algorithm function object)
ranges::copy_n

(C++20)

将一定数量的元素复制到新位置
(algorithm function object)
ranges::copy_backward

(C++20)

以向后顺序复制元素范围
(algorithm function object)
ranges::move

(C++20)

将元素范围移动到新位置
(algorithm function object)
ranges::move_backward

(C++20)

以向后顺序将元素范围移动到新位置
(algorithm function object)
ranges::fill

(C++20)

为元素范围赋值
(algorithm function object)
ranges::fill_n

(C++20)

为若干元素赋值
(algorithm function object)
ranges::transform

(C++20)

将函数应用于元素范围
(algorithm function object)
ranges::generate

(C++20)

将函数结果保存在范围中
(algorithm function object)
ranges::generate_n

(C++20)

保存函数 N 次应用的结果
(algorithm function object)
ranges::remove
ranges::remove_if

(C++20)
(C++20)

移除满足特定条件的元素
(algorithm function object)
ranges::remove_copy
ranges::remove_copy_if

(C++20)
(C++20)

复制元素范围,省略那些满足特定条件的元素
(algorithm function object)
ranges::replace
ranges::replace_if

(C++20)
(C++20)

将所有满足特定条件的值替换为另一个值
(algorithm function object)
ranges::replace_copy
ranges::replace_copy_if

(C++20)
(C++20)

复制一个范围,将满足特定条件的元素替换为另一个值
(algorithm function object)
ranges::swap_ranges

(C++20)

交换两个元素范围
(algorithm function object)
ranges::reverse

(C++20)

反转范围中元素的顺序
(algorithm function object)
ranges::reverse_copy

(C++20)

创建一个反转的范围副本
(algorithm function object)
ranges::rotate

(C++20)

旋转范围中元素的顺序
(algorithm function object)
ranges::rotate_copy

(C++20)

复制并旋转元素范围
(algorithm function object)
ranges::shift_left
ranges::shift_right

(C++23)

移动范围中的元素
(algorithm function object)
ranges::sample

(C++20)

从序列中选择 N 个随机元素
(algorithm function object)
ranges::shuffle

(C++20)

随机重新排序范围中的元素
(algorithm function object)
ranges::unique

(C++20)

移除范围中连续重复的元素
(algorithm function object)
ranges::unique_copy

(C++20)

创建某个元素范围的副本,其中不包含连续重复项
(algorithm function object)
分区操作
ranges::is_partitioned

(C++20)

确定范围是否由给定谓词分区
(algorithm function object)
ranges::partition

(C++20)

将元素范围划分为两组
(algorithm function object)
ranges::partition_copy

(C++20)

复制一个范围,将元素划分为两组
(algorithm function object)
ranges::stable_partition

(C++20)

将元素划分为两组,同时保持其相对顺序
(algorithm function object)
ranges::partition_point

(C++20)

定位已分区范围的分区点
(algorithm function object)
排序操作
ranges::is_sorted

(C++20)

检查范围是否已排序为升序
(algorithm function object)
ranges::is_sorted_until

(C++20)

查找最大的已排序子范围
(algorithm function object)
ranges::sort

(C++20)

将范围排序为升序
(algorithm function object)
ranges::partial_sort

(C++20)

对范围的前 N 个元素进行排序
(algorithm function object)
ranges::partial_sort_copy

(C++20)

复制并部分排序元素范围
(algorithm function object)
ranges::stable_sort

(C++20)

排序元素范围,同时保持相等元素之间的顺序
(algorithm function object)
ranges::nth_element

(C++20)

部分排序给定范围,确保它按给定元素分区
(algorithm function object)
二分搜索操作 (在已排序范围上)
ranges::lower_bound

(C++20)

返回指向第一个不小于给定值的元素的迭代器
(algorithm function object)
ranges::upper_bound

(C++20)

返回指向首个大于某值的元素的迭代器
(algorithm function object)
ranges::binary_search

(C++20)

确定元素是否存在于部分有序的范围内
(algorithm function object)
ranges::equal_range

(C++20)

返回与特定键匹配的元素范围
(algorithm function object)
其他排序范围上的操作
ranges::merge

(C++20)

合并两个已排序的范围
(algorithm function object)
ranges::inplace_merge

(C++20)

就地合并两个有序范围
(algorithm function object)
集合操作(在已排序的范围上)
ranges::includes

(C++20)

如果一个序列是另一个序列的子序列,则返回 true
(algorithm function object)
ranges::set_difference

(C++20)

计算两个集合的差集
(algorithm function object)
ranges::set_intersection

(C++20)

计算两个集合的交集
(algorithm function object)
ranges::set_symmetric_difference

(C++20)

计算两个集合的对称差集
(algorithm function object)
ranges::set_union

(C++20)

计算两个集合的并集
(algorithm function object)
堆操作
ranges::is_heap

(C++20)

检查给定范围是否为最大堆
(algorithm function object)
ranges::is_heap_until

(C++20)

查找作为最大堆的最大子范围
(algorithm function object)
ranges::make_heap

(C++20)

从元素范围创建最大堆
(algorithm function object)
ranges::push_heap

(C++20)

向最大堆添加元素
(algorithm function object)
ranges::pop_heap

(C++20)

从最大堆中移除最大的元素
(algorithm function object)
ranges::sort_heap

(C++20)

将最大堆转换为升序排序的元素范围
(algorithm function object)
最小值/最大值操作
ranges::max

(C++20)

返回给定值中较大的那个
(algorithm function object)
ranges::max_element

(C++20)

返回范围中最大的元素
(algorithm function object)
ranges::min

(C++20)

返回给定值中较小的那个
(algorithm function object)
ranges::min_element

(C++20)

返回范围中最小的元素
(algorithm function object)
ranges::minmax

(C++20)

返回两个元素中较小和较大的那个
(algorithm function object)
ranges::minmax_element

(C++20)

返回范围中最小和最大的元素
(algorithm function object)
ranges::clamp

(C++20)

将值限制在边界值对之间
(algorithm function object)
比较操作
ranges::equal

(C++20)

确定两组元素是否相同
(algorithm function object)
ranges::lexicographical_compare

(C++20)

如果一个范围在字典序上小于另一个范围,则返回 true
(算法函数对象)
排列操作
ranges::is_permutation

(C++20)

确定一个序列是否是另一个序列的排列
(算法函数对象)
ranges::next_permutation

(C++20)

生成元素范围的下一个更大的字典序排列
(算法函数对象)
ranges::prev_permutation

(C++20)

生成元素范围的下一个更小的字典序排列
(算法函数对象)
概要
#include <initializer_list>

namespace std {
  namespace ranges {
    // algorithm result types
    template<class I, class F>
      struct in_fun_result;

    template<class I1, class I2>
      struct in_in_result;

    template<class I, class O>
      struct in_out_result;

    template<class I1, class I2, class O>
      struct in_in_out_result;

    template<class I, class O1, class O2>
      struct in_out_out_result;

    template<class T>
      struct min_max_result;

    template<class I>
      struct in_found_result;

    template<class I, class T>
      struct in_value_result;

    template<class O, class T>
      struct out_value_result;
  }

  // non-modifying sequence operations
  // all of
  template<class InputIter, class Pred>
    constexpr bool all_of(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool all_of(ExecutionPolicy&& exec,
                ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool all_of(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool all_of(R&& r, Pred pred, Proj proj = {});
  }

  // any of
  template<class InputIter, class Pred>
    constexpr bool any_of(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool any_of(ExecutionPolicy&& exec,
                ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool any_of(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool any_of(R&& r, Pred pred, Proj proj = {});
  }

  // none of
  template<class InputIter, class Pred>
    constexpr bool none_of(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool none_of(ExecutionPolicy&& exec,
                 ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool none_of(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool none_of(R&& r, Pred pred, Proj proj = {});
  }

  // contains
  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr bool contains(I first, S last, const T& value, Proj proj = {});
    template<input_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>>
      requires indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr bool contains(R&& r, const T& value, Proj proj = {});

    template<forward_iterator I1, sentinel_for<I1> S1,
             forward_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity,
             class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2,
                                       Pred pred = {}, Proj1 proj1 = {},
                                       Proj2 proj2 = {});
    template<forward_range R1, forward_range R2,
             class Pred = ranges::equal_to, class Proj1 = identity,
             class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool contains_subrange(R1&& r1, R2&& r2,
                                       Pred pred = {}, Proj1 proj1 = {},
                                       Proj2 proj2 = {});
  }

  // for each
  template<class InputIter, class Function>
    constexpr Function for_each(InputIter first, InputIter last, Function f);
  template<class ExecutionPolicy, class ForwardIter, class Function>
    void for_each(ExecutionPolicy&& exec,
                  ForwardIter first, ForwardIter last, Function f);

  namespace ranges {
    template<class I, class F>
      using for_each_result = in_fun_result<I, F>;

    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirectly_unary_invocable<projected<I, Proj>> Fun>
      constexpr for_each_result<I, Fun>
        for_each(I first, S last, Fun f, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirectly_unary_invocable<projected<iterator_t<R>, Proj>> Fun>
      constexpr for_each_result<borrowed_iterator_t<R>, Fun>
        for_each(R&& r, Fun f, Proj proj = {});
  }

  template<class InputIter, class Size, class Function>
    constexpr InputIter for_each_n(InputIter first, Size n, Function f);
  template<class ExecutionPolicy, class ForwardIter, class Size, class Function>
    ForwardIter for_each_n(ExecutionPolicy&& exec,
                           ForwardIter first, Size n, Function f);

  namespace ranges {
    template<class I, class F>
      using for_each_n_result = in_fun_result<I, F>;

    template<input_iterator I, class Proj = identity,
             indirectly_unary_invocable<projected<I, Proj>> Fun>
      constexpr for_each_n_result<I, Fun>
        for_each_n(I first, iter_difference_t<I> n, Fun f, Proj proj = {});
  }

  // find
  template<class InputIter, class T = typename iterator_traits<InputIter>::value_type>
    constexpr InputIter find(InputIter first, InputIter last, const T& value);
  template<class ExecutionPolicy, class ForwardIter,
           class T = typename iterator_traits<InputIter>::value_type>
    ForwardIter find(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last, const T& value);
  template<class InputIter, class Pred>
    constexpr InputIter find_if(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter find_if(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last, Pred pred);
  template<class InputIter, class Pred>
    constexpr InputIter find_if_not(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter find_if_not(ExecutionPolicy&& exec,
                            ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity
             class T = projected_value_t<I, Proj>>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr I find(I first, S last, const T& value, Proj proj = {});
    template<input_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>>
      requires indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr borrowed_iterator_t<R>
        find(R&& r, const T& value, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr I find_if(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_iterator_t<R>
        find_if(R&& r, Pred pred, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr I find_if_not(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_iterator_t<R>
        find_if_not(R&& r, Pred pred, Proj proj = {});
  }

  // find last
  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr subrange<I> find_last(I first, S last, const T& value, Proj proj = {});
    template<forward_range R, class T, class Proj = identity>
      requires
        indirect_binary_predicate<ranges::equal_to,
            projected<iterator_t<R>, Proj>, const T*>
      constexpr borrowed_subrange_t<R> find_last(R&& r, const T& value, Proj proj = {});
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr subrange<I> find_last_if(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_subrange_t<R> find_last_if(R&& r, Pred pred, Proj proj = {});
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr subrange<I> find_last_if_not(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_subrange_t<R> find_last_if_not(R&& r, Pred pred, Proj proj = {});
  }

  // find end
  template<class ForwardIter1, class ForwardIter2>
    constexpr ForwardIter1
      find_end(ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr ForwardIter1
      find_end(ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter1
      find_end(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1,
           class ForwardIter2, class BinaryPred>
    ForwardIter1
      find_end(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);

  namespace ranges {
    template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr subrange<I1>
        find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<forward_range R1, forward_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr borrowed_subrange_t<R1>
        find_end(R1&& r1, R2&& r2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // find first
  template<class InputIter, class ForwardIter>
    constexpr InputIter
      find_first_of(InputIter first1, InputIter last1,
                    ForwardIter first2, ForwardIter last2);
  template<class InputIter, class ForwardIter, class BinaryPred>
    constexpr InputIter
      find_first_of(InputIter first1, InputIter last1,
                    ForwardIter first2, ForwardIter last2,
                    BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter1
      find_first_of(ExecutionPolicy&& exec,
                    ForwardIter1 first1, ForwardIter1 last1,
                    ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1,
           class ForwardIter2, class BinaryPred>
    ForwardIter1
      find_first_of(ExecutionPolicy&& exec,
                    ForwardIter1 first1, ForwardIter1 last1,
                    ForwardIter2 first2, ForwardIter2 last2,
                    BinaryPred pred);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr I1 find_first_of(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, forward_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr borrowed_iterator_t<R1>
        find_first_of(R1&& r1, R2&& r2, Pred pred = {},
                      Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // adjacent find
  template<class ForwardIter>
    constexpr ForwardIter adjacent_find(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class BinaryPred>
    constexpr ForwardIter adjacent_find(ForwardIter first, ForwardIter last,
                                        BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter adjacent_find(ExecutionPolicy&& exec,
                              ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class BinaryPred>
    ForwardIter adjacent_find(ExecutionPolicy&& exec,
                              ForwardIter first, ForwardIter last, BinaryPred pred);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_binary_predicate<projected<I, Proj>,
                                       projected<I, Proj>> Pred = ranges::equal_to>
      constexpr I adjacent_find(I first, S last, Pred pred = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_binary_predicate<projected<iterator_t<R>, Proj>,
                                       projected<iterator_t<R>, Proj>>
                                         Pred = ranges::equal_to>
      constexpr borrowed_iterator_t<R>
        adjacent_find(R&& r, Pred pred = {}, Proj proj = {});
  }

  // count
  template<class InputIter, class T = typename iterator_traits<InputIter>::value_type>
    constexpr typename iterator_traits<InputIter>::difference_type
      count(InputIter first, InputIter last, const T& value);
  template<class ExecutionPolicy, class ForwardIter,
           class T = typename iterator_traits<InputIterator>::value_type>
    typename iterator_traits<ForwardIter>::difference_type
      count(ExecutionPolicy&& exec,
            ForwardIter first, ForwardIter last, const T& value);
  template<class InputIter, class Pred>
    constexpr typename iterator_traits<InputIter>::difference_type
      count_if(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    typename iterator_traits<ForwardIter>::difference_type
      count_if(ExecutionPolicy&& exec,
               ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr iter_difference_t<I>
        count(I first, S last, const T& value, Proj proj = {});
    template<input_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>>
      requires indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr range_difference_t<R>
        count(R&& r, const T& value, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr iter_difference_t<I>
        count_if(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr range_difference_t<R>
        count_if(R&& r, Pred pred, Proj proj = {});
  }

  // mismatch
  template<class InputIter1, class InputIter2>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2, BinaryPred pred);
  template<class InputIter1, class InputIter2>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2, InputIter2 last2,
               BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);

  namespace ranges {
    template<class I1, class I2>
      using mismatch_result = in_in_result<I1, I2>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = identity,
             class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr mismatch_result<I1, I2>
        mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2,
             class Pred = ranges::equal_to, class Proj1 = identity,
             class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr mismatch_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
        mismatch(R1&& r1, R2&& r2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // equal
  template<class InputIter1, class InputIter2>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2, BinaryPred pred);
  template<class InputIter1, class InputIter2>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2, InputIter2 last2,
                         BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = identity,
             class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool equal(I1 first1, S1 last1, I2 first2, S2 last2,
                           Pred pred = {},
                           Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool equal(R1&& r1, R2&& r2, Pred pred = {},
                           Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // is permutation
  template<class ForwardIter1, class ForwardIter2>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2, BinaryPred pred);
  template<class ForwardIter1, class ForwardIter2>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2, ForwardIter2 last2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2, ForwardIter2 last2,
                                  BinaryPred pred);

  namespace ranges {
    template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
             sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
             indirect_equivalence_relation<projected<I1, Proj1>,
                                           projected<I2, Proj2>> Pred = ranges::equal_to>
      constexpr bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
                                    Pred pred = {},
                                    Proj1 proj1 = {}, Proj2 proj2 = {});
    template<forward_range R1, forward_range R2,
             class Proj1 = identity, class Proj2 = identity,
             indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>,
                                           projected<iterator_t<R2>, Proj2>>
                                           Pred = ranges::equal_to>
      constexpr bool is_permutation(R1&& r1, R2&& r2, Pred pred = {},
                                    Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // search
  template<class ForwardIter1, class ForwardIter2>
    constexpr ForwardIter1
      search(ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr ForwardIter1
      search(ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter1
      search(ExecutionPolicy&& exec,
             ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    ForwardIter1
      search(ExecutionPolicy&& exec,
             ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2, BinaryPred pred);

  namespace ranges {
    template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr subrange<I1>
        search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {});
    template<forward_range R1, forward_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr borrowed_subrange_t<R1>
        search(R1&& r1, R2&& r2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class ForwardIter, class Size,
           class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr ForwardIter
      search_n(ForwardIter first, ForwardIter last,
               Size count, const T& value);
  template<class ForwardIter, class Size,
           class T = typename iterator_traits<ForwardIter>::value_type, class BinaryPred>
    constexpr ForwardIter
      search_n(ForwardIter first, ForwardIter last,
               Size count, const T& value, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter, class Size,
           class T = typename iterator_traits<ForwardIter>::value_type>
    ForwardIter
      search_n(ExecutionPolicy&& exec,
               ForwardIter first, ForwardIter last,
               Size count, const T& value);
  template<class ExecutionPolicy, class ForwardIter, class Size,
           class T = typename iterator_traits<ForwardIter>::value_type, class BinaryPred>
    ForwardIter
      search_n(ExecutionPolicy&& exec,
               ForwardIter first, ForwardIter last,
               Size count, const T& value, BinaryPred pred);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S,
             class Pred = ranges::equal_to, class Proj = identity,
             class T = projected_value_t<I, Proj>>
      requires indirectly_comparable<I, const T*, Pred, Proj>
      constexpr subrange<I>
        search_n(I first, S last, iter_difference_t<I> count,
                 const T& value, Pred pred = {}, Proj proj = {});
    template<forward_range R, class Pred = ranges::equal_to, class Proj = identity,
             projected_value_t<iterator_t<R>, Proj>>
      requires indirectly_comparable<iterator_t<R>, const T*, Pred, Proj>
      constexpr borrowed_subrange_t<R>
        search_n(R&& r, range_difference_t<R> count,
                 const T& value, Pred pred = {}, Proj proj = {});
  }

  template<class ForwardIter, class Searcher>
    constexpr ForwardIter
      search(ForwardIter first, ForwardIter last, const Searcher& searcher);

  namespace ranges {
    // starts with
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool starts_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool starts_with(R1&& r1, R2&& r2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});

    // ends with
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires (forward_iterator<I1> || sized_sentinel_for<S1, I1>) &&
               (forward_iterator<I2> || sized_sentinel_for<S2, I2>) &&
               indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                               Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires (forward_range<R1> || sized_range<R1>) &&
               (forward_range<R2> || sized_range<R2>) &&
               indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},
                               Proj1 proj1 = {}, Proj2 proj2 = {});

    // fold
    template<class F>
    class /* flipped */ {   // exposition only
      F f;                  // exposition only

    public:
      template<class T, class U> requires invocable<F&, U, T>
      invoke_result_t<F&, U, T> operator()(T&&, U&&);
    };

    template<class F, class T, class I, class U>
      concept /* indirectly-binary-left-foldable-impl */ =  // exposition only
        movable<T> && movable<U> &&
        convertible_to<T, U> && invocable<F&, U, iter_reference_t<I>> &&
        assignable_from<U&, invoke_result_t<F&, U, iter_reference_t<I>>>;

    template<class F, class T, class I>
      concept /* indirectly-binary-left-foldable */ =       // exposition only
        copy_constructible<F> && indirectly_readable<I> &&
        invocable<F&, T, iter_reference_t<I>> &&
        convertible_to<invoke_result_t<F&, T, iter_reference_t<I>>,
               decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>> &&
        /* indirectly-binary-left-foldable-impl */
             <F, T, I, decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>>;

    template<class F, class T, class I>
      concept /* indirectly-binary-right-foldable */ =      // exposition only
        /* indirectly-binary-left-foldable */</* flipped */<F>, T, I>;

    template<input_iterator I, sentinel_for<I> S, class T = iter_value_t<I>,
             /* indirectly-binary-left-foldable */<T, I> F>
      constexpr auto fold_left(I first, S last, T init, F f);

    template<input_range R, class T = range_value_t<R>,
             /* indirectly-binary-left-foldable */<T, iterator_t<R>> F>
      constexpr auto fold_left(R&& r, T init, F f);

    template<input_iterator I, sentinel_for<I> S,
             /* indirectly-binary-left-foldable */<iter_value_t<I>, I> F>
      requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
      constexpr auto fold_left_first(I first, S last, F f);

    template<input_range R,
             /* indirectly-binary-left-foldable */<range_value_t<R>, iterator_t<R>> F>
      requires constructible_from<range_value_t<R>, range_reference_t<R>>
      constexpr auto fold_left_first(R&& r, F f);

    template<bidirectional_iterator I, sentinel_for<I> S, class T = iter_value_t<I>,
             /* indirectly-binary-right-foldable */<T, I> F>
      constexpr auto fold_right(I first, S last, T init, F f);

    template<bidirectional_range R, class T = range_value_t<R>,
             /* indirectly-binary-right-foldable */<T, iterator_t<R>> F>
      constexpr auto fold_right(R&& r, T init, F f);

    template<bidirectional_iterator I, sentinel_for<I> S,
             /* indirectly-binary-right-foldable */<iter_value_t<I>, I> F>
      requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
    constexpr auto fold_right_last(I first, S last, F f);

    template<bidirectional_range R,
             /* indirectly-binary-right-foldable */<range_value_t<R>, iterator_t<R>> F>
      requires constructible_from<range_value_t<R>, range_reference_t<R>>
      constexpr auto fold_right_last(R&& r, F f);

    template<class I, class T>
      using fold_left_with_iter_result = in_value_result<I, T>;
    template<class I, class T>
      using fold_left_first_with_iter_result = in_value_result<I, T>;

    template<input_iterator I, sentinel_for<I> S, class T = iter_value_t<I>,
             /* indirectly-binary-left-foldable */<T, I> F>
      constexpr /* see description */ fold_left_with_iter(I first, S last, T init, F f);

    template<input_range R, class T = range_value_t<R>,
             /* indirectly-binary-left-foldable */<T, iterator_t<R>> F>
      constexpr /* see description */ fold_left_with_iter(R&& r, T init, F f);

    template<input_iterator I, sentinel_for<I> S,
             /* indirectly-binary-left-foldable */<iter_value_t<I>, I> F>
      requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
      constexpr /* see description */ fold_left_first_with_iter(I first, S last, F f);

    template<input_range R,
             /* indirectly-binary-left-foldable */<range_value_t<R>, iterator_t<R>> F>
      requires constructible_from<range_value_t<R>, range_reference_t<R>>
      constexpr /* see description */ fold_left_first_with_iter(R&& r, F f);
  }

  // mutating sequence operations
  // copy
  template<class InputIter, class OutputIter>
    constexpr OutputIter copy(InputIter first, InputIter last,
                              OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2 copy(ExecutionPolicy&& exec,
                      ForwardIter1 first, ForwardIter1 last,
                      ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr copy_result<I, O> copy(I first, S last, O result);
    template<input_range R, weakly_incrementable O>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr copy_result<borrowed_iterator_t<R>, O> copy(R&& r, O result);
  }

  template<class InputIter, class Size, class OutputIter>
    constexpr OutputIter copy_n(InputIter first, Size n, OutputIter result);
  template<class ExecutionPolicy,
           class ForwardIter1, class Size, class ForwardIter2>
    ForwardIter2 copy_n(ExecutionPolicy&& exec,
                        ForwardIter1 first, Size n, ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using copy_n_result = in_out_result<I, O>;

    template<input_iterator I, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr copy_n_result<I, O> copy_n(I first, iter_difference_t<I> n, O result);
  }

  template<class InputIter, class OutputIter, class Pred>
    constexpr OutputIter copy_if(InputIter first, InputIter last,
                                 OutputIter result, Pred pred);
  template<class ExecutionPolicy,
           class ForwardIter1, class ForwardIter2, class Pred>
    ForwardIter2 copy_if(ExecutionPolicy&& exec,
                         ForwardIter1 first, ForwardIter1 last,
                         ForwardIter2 result, Pred pred);

  namespace ranges {
    template<class I, class O>
      using copy_if_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O>
      constexpr copy_if_result<I, O>
        copy_if(I first, S last, O result, Pred pred, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr copy_if_result<borrowed_iterator_t<R>, O>
        copy_if(R&& r, O result, Pred pred, Proj proj = {});
  }

  template<class BidirectionalIter1, class BidirectionalIter2>
    constexpr BidirectionalIter2
      copy_backward(BidirectionalIter1 first, BidirectionalIter1 last,
                    BidirectionalIter2 result);

  namespace ranges {
    template<class I1, class I2>
      using copy_backward_result = in_out_result<I1, I2>;

    template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
      requires indirectly_copyable<I1, I2>
      constexpr copy_backward_result<I1, I2>
        copy_backward(I1 first, S1 last, I2 result);
    template<bidirectional_range R, bidirectional_iterator I>
      requires indirectly_copyable<iterator_t<R>, I>
      constexpr copy_backward_result<borrowed_iterator_t<R>, I>
        copy_backward(R&& r, I result);
  }

  // move
  template<class InputIter, class OutputIter>
    constexpr OutputIter move(InputIter first, InputIter last, OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1,
           class ForwardIter2>
    ForwardIter2 move(ExecutionPolicy&& exec,
                      ForwardIter1 first, ForwardIter1 last, ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using move_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_movable<I, O>
      constexpr move_result<I, O> move(I first, S last, O result);
    template<input_range R, weakly_incrementable O>
      requires indirectly_movable<iterator_t<R>, O>
      constexpr move_result<borrowed_iterator_t<R>, O> move(R&& r, O result);
  }

  template<class BidirectionalIter1, class BidirectionalIter2>
    constexpr BidirectionalIter2
      move_backward(BidirectionalIter1 first, BidirectionalIter1 last,
                    BidirectionalIter2 result);

  namespace ranges {
    template<class I1, class I2>
      using move_backward_result = in_out_result<I1, I2>;

    template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
      requires indirectly_movable<I1, I2>
      constexpr move_backward_result<I1, I2>
        move_backward(I1 first, S1 last, I2 result);
    template<bidirectional_range R, bidirectional_iterator I>
      requires indirectly_movable<iterator_t<R>, I>
      constexpr move_backward_result<borrowed_iterator_t<R>, I>
        move_backward(R&& r, I result);
  }

  // swap
  template<class ForwardIter1, class ForwardIter2>
    constexpr ForwardIter2 swap_ranges(ForwardIter1 first1, ForwardIter1 last1,
                                       ForwardIter2 first2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2 swap_ranges(ExecutionPolicy&& exec,
                             ForwardIter1 first1, ForwardIter1 last1,
                             ForwardIter2 first2);

  namespace ranges {
    template<class I1, class I2>
      using swap_ranges_result = in_in_result<I1, I2>;

    template<input_iterator I1, sentinel_for<I1> S1,
             input_iterator I2, sentinel_for<I2> S2>
      requires indirectly_swappable<I1, I2>
      constexpr swap_ranges_result<I1, I2>
        swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
    template<input_range R1, input_range R2>
      requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>>
      constexpr swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
        swap_ranges(R1&& r1, R2&& r2);
  }

  template<class ForwardIter1, class ForwardIter2>
    constexpr void iter_swap(ForwardIter1 a, ForwardIter2 b);

  // transform
  template<class InputIter, class OutputIter, class UnaryOperation>
    constexpr OutputIter
      transform(InputIter first1, InputIter last1,
                OutputIter result, UnaryOperation op);
  template<class InputIter1, class InputIter2, class OutputIter,
           class BinaryOperation>
    constexpr OutputIter
      transform(InputIter1 first1, InputIter1 last1,
                InputIter2 first2, OutputIter result,
                BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class UnaryOperation>
    ForwardIter2
      transform(ExecutionPolicy&& exec,
                ForwardIter1 first1, ForwardIter1 last1,
                ForwardIter2 result, UnaryOperation op);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class BinaryOperation>
    ForwardIter
      transform(ExecutionPolicy&& exec,
                ForwardIter1 first1, ForwardIter1 last1,
                ForwardIter2 first2, ForwardIter result,
                BinaryOperation binary_op);

  namespace ranges {
    template<class I, class O>
      using unary_transform_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
             copy_constructible F, class Proj = identity>
      requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
      constexpr unary_transform_result<I, O>
        transform(I first1, S last1, O result, F op, Proj proj = {});
    template<input_range R, weakly_incrementable O,
             copy_constructible F, class Proj = identity>
      requires
        indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
      constexpr unary_transform_result<borrowed_iterator_t<R>, O>
        transform(R&& r, O result, F op, Proj proj = {});

    template<class I1, class I2, class O>
      using binary_transform_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, weakly_incrementable O, copy_constructible F,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
                                                        projected<I2, Proj2>>>
      constexpr binary_transform_result<I1, I2, O>
        transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                  F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             copy_constructible F, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_writable
                   <O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>, 
                                         projected<iterator_t<R2>, Proj2>>>
      constexpr binary_transform_result<borrowed_iterator_t<R1>,
                                        borrowed_iterator_t<R2>, O>
        transform(R1&& r1, R2&& r2, O result,
                  F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // replace
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr void replace(ForwardIter first, ForwardIter last,
                           const T& old_value, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter,
           class T = typename iterator_traits<ForwardIter>::value_type>
    void replace(ExecutionPolicy&& exec,
                 ForwardIter first, ForwardIter last,
                 const T& old_value, const T& new_value);
  template<class ForwardIter, class Pred,
           class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr void replace_if(ForwardIter first, ForwardIter last,
                              Pred pred, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter, class Pred,
           class T = typename iterator_traits<ForwardIter>::value_type>
    void replace_if(ExecutionPolicy&& exec,
                    ForwardIter first, ForwardIter last,
                    Pred pred, const T& new_value);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S,
             class Proj = identity, class T1 = projected_value_t<I, Proj>, class T2 = T1>
      requires indirectly_writable<I, const T2&> &&
               indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
      constexpr I replace(I first, S last, const T1& old_value,
                          const T2& new_value, Proj proj = {});
    template<input_range R, class Proj = identity,
             class T1 = projected_value_t<iterator_t<R>, Proj>, class T2 = T1>
      requires indirectly_writable<iterator_t<R>, const T2&> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T1*>
      constexpr borrowed_iterator_t<R> replace(R&& r, const T1& old_value,
                                               const T2& new_value, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_writable<I, const T&>
      constexpr I replace_if(I first, S last, Pred pred,
                             const T& new_value, Proj proj = {});
    template<input_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_writable<iterator_t<R>, const T&>
      constexpr borrowed_iterator_t<R> replace_if(R&& r, Pred pred,
                                                  const T& new_value, Proj proj = {});
  }

  template<class InputIter, class OutputIter, class T>
    constexpr OutputIter replace_copy(InputIter first, InputIter last, OutputIter result,
                                      const T& old_value, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class T>
    ForwardIter2 replace_copy(ExecutionPolicy&& exec,
                              ForwardIter1 first, ForwardIter1 last, ForwardIter2 result,
                              const T& old_value, const T& new_value);
  template<class InputIter, class OutputIter, class Pred,
           class T = typename iterator_traits<OutputIter>::value_type>
    constexpr OutputIter replace_copy_if(InputIter first, InputIter last,
                                         OutputIter result,
                                         Pred pred, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Pred, class T = typename iterator_traits<ForwardIter2>::value_type>
    ForwardIter2 replace_copy_if(ExecutionPolicy&& exec,
                                 ForwardIter1 first, ForwardIter1 last,
                                 ForwardIter2 result,
                                 Pred pred, const T& new_value);

  namespace ranges {
    template<class I, class O>
      using replace_copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, class O, class Proj = identity,
             class T1 = projected_value_t<I, Proj>, class T2 = iter_value_t<O>>
      requires indirectly_copyable<I, O> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<I, Proj>, const T1*> &&
               output_iterator<O, const T2&>
      constexpr replace_copy_result<I, O>
        replace_copy(I first, S last, O result, const T1& old_value,
                     const T2& new_value, Proj proj = {});
    template<input_range R, class O, class Proj = identity,
             class T1 = projected_value_t<iterator_t<R>, Proj>,
             class T2 = iter_value_t<O>>
      requires indirectly_copyable<iterator_t<R>, O> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T1*> &&
               output_iterator<O, const T2&>
      constexpr replace_copy_result<borrowed_iterator_t<R>, O>
        replace_copy(R&& r, O result, const T1& old_value,
                     const T2& new_value, Proj proj = {});

    template<class I, class O>
      using replace_copy_if_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, class O, class T = iter_value_t<O>,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O> && output_iterator<O, const T&>
      constexpr replace_copy_if_result<I, O>
        replace_copy_if(I first, S last, O result, Pred pred,
                        const T& new_value, Proj proj = {});
    template<input_range R, class O, class T = iter_value_t<O>, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O> && output_iterator<O, const T&>
      constexpr replace_copy_if_result<borrowed_iterator_t<R>, O>
        replace_copy_if(R&& r, O result, Pred pred,
                        const T& new_value, Proj proj = {});
  }

  // fill
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr void fill(ForwardIter first, ForwardIter last, const T& value);
  template<class ExecutionPolicy, class ForwardIter,
           class T = typename iterator_traits<ForwardIter>::value_type>
    void fill(ExecutionPolicy&& exec,
              ForwardIter first, ForwardIter last, const T& value);
  template<class OutputIter, class Size,
           class T = typename iterator_traits<OutputIter>::value_type>
    constexpr OutputIter fill_n(OutputIter first, Size n, const T& value);
  template<class ExecutionPolicy, class ForwardIter,
           class Size, class T = typename iterator_traits<OutputIter>::value_type>
    ForwardIter fill_n(ExecutionPolicy&& exec,
                       ForwardIter first, Size n, const T& value);

  namespace ranges {
    template<class O, sentinel_for<O> S, class T = iter_value_t<O>>
      requires output_iterator<O, const T&>
      constexpr O fill(O first, S last, const T& value);
    template<class R, class T = range_value_t<R>>
      requires output_range<R, const T&>
      constexpr borrowed_iterator_t<R> fill(R&& r, const T& value);
    template<class O, class T = iter_value_t<O>>
      requires output_iterator<O, const T&>
      constexpr O fill_n(O first, iter_difference_t<O> n, const T& value);
  }

  // generate
  template<class ForwardIter, class Generator>
    constexpr void generate(ForwardIter first, ForwardIter last, Generator gen);
  template<class ExecutionPolicy, class ForwardIter, class Generator>
    void generate(ExecutionPolicy&& exec,
                  ForwardIter first, ForwardIter last, Generator gen);
  template<class OutputIter, class Size, class Generator>
    constexpr OutputIter generate_n(OutputIter first, Size n, Generator gen);
  template<class ExecutionPolicy, class ForwardIter, class Size, class Generator>
    ForwardIter generate_n(ExecutionPolicy&& exec,
                           ForwardIter first, Size n, Generator gen);

  namespace ranges {
    template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
      requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
      constexpr O generate(O first, S last, F gen);
    template<class R, copy_constructible F>
      requires invocable<F&> && output_range<R, invoke_result_t<F&>>
      constexpr borrowed_iterator_t<R> generate(R&& r, F gen);
    template<input_or_output_iterator O, copy_constructible F>
      requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
      constexpr O generate_n(O first, iter_difference_t<O> n, F gen);
  }

  // remove
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr ForwardIter remove(ForwardIter first, ForwardIter last, const T& value);
  template<class ExecutionPolicy, class ForwardIter,
           class T = typename iterator_traits<ForwardIter>::value_type>
    ForwardIter remove(ExecutionPolicy&& exec,
                       ForwardIter first, ForwardIter last, const T& value);
  template<class ForwardIter, class Pred>
    constexpr ForwardIter remove_if(ForwardIter first, ForwardIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter remove_if(ExecutionPolicy&& exec,
                          ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr subrange<I> remove(I first, S last, const T& value, Proj proj = {});
    template<forward_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>>
      requires permutable<iterator_t<R>> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr borrowed_subrange_t<R> remove(R&& r, const T& value, Proj proj = {});
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr subrange<I> remove_if(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> remove_if(R&& r, Pred pred, Proj proj = {});
  }

  template<class InputIter, class OutputIter,
           class T = typename iterator_traits<InputIter>::value_type>
    constexpr OutputIter remove_copy(InputIter first, InputIter last,
                                     OutputIter result, const T& value);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class T = typename iterator_traits<ForwardIter1>::value_type>
    ForwardIter2 remove_copy(ExecutionPolicy&& exec,
                             ForwardIter1 first, ForwardIter1 last,
                             ForwardIter2 result, const T& value);
  template<class InputIter, class OutputIter, class Pred>
    constexpr OutputIter remove_copy_if(InputIter first, InputIter last,
                                        OutputIter result, Pred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class Pred>
    ForwardIter2 remove_copy_if(ExecutionPolicy&& exec,
                                ForwardIter1 first, ForwardIter1 last,
                                ForwardIter2 result, Pred pred);

  namespace ranges {
    template<class I, class O>
      using remove_copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
             class Proj = identity, class T = projected_value_t<I, Proj>>
      requires indirectly_copyable<I, O> &&
               indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr remove_copy_result<I, O>
        remove_copy(I first, S last, O result, const T& value, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>>
      requires indirectly_copyable<iterator_t<R>, O> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr remove_copy_result<borrowed_iterator_t<R>, O>
        remove_copy(R&& r, O result, const T& value, Proj proj = {});

    template<class I, class O>
      using remove_copy_if_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O>
      constexpr remove_copy_if_result<I, O>
        remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr remove_copy_if_result<borrowed_iterator_t<R>, O>
        remove_copy_if(R&& r, O result, Pred pred, Proj proj = {});
  }

  // unique
  template<class ForwardIter>
    constexpr ForwardIter unique(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class BinaryPred>
    constexpr ForwardIter unique(ForwardIter first, ForwardIter last, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter unique(ExecutionPolicy&& exec,
                       ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class BinaryPred>
    ForwardIter unique(ExecutionPolicy&& exec,
                       ForwardIter first, ForwardIter last, BinaryPred pred);

  namespace ranges {
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
      constexpr subrange<I> unique(I first, S last, C comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_equivalence_relation
                 <projected<iterator_t<R>, Proj>> C = ranges::equal_to>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> unique(R&& r, C comp = {}, Proj proj = {});
  }

  template<class InputIter, class OutputIter>
    constexpr OutputIter unique_copy(InputIter first, InputIter last,
                                     OutputIter result);
  template<class InputIter, class OutputIter, class BinaryPred>
    constexpr OutputIter unique_copy(InputIter first, InputIter last,
                                     OutputIter result, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2 unique_copy(ExecutionPolicy&& exec,
                             ForwardIter1 first, ForwardIter1 last,
                             ForwardIter2 result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    ForwardIter2 unique_copy(ExecutionPolicy&& exec,
                             ForwardIter1 first, ForwardIter1 last,
                             ForwardIter2 result, BinaryPred pred);

  namespace ranges {
    template<class I, class O>
      using unique_copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S,
             weakly_incrementable O, class Proj = identity,
             indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
      requires indirectly_copyable<I, O> &&
               (forward_iterator<I> ||
                (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
                indirectly_copyable_storable<I, O>)
      constexpr unique_copy_result<I, O>
        unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             indirect_equivalence_relation
                 <projected<iterator_t<R>, Proj>> C = ranges::equal_to>
      requires indirectly_copyable<iterator_t<R>, O> &&
               (forward_iterator<iterator_t<R>> ||
                (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
                indirectly_copyable_storable<iterator_t<R>, O>)
      constexpr unique_copy_result<borrowed_iterator_t<R>, O>
        unique_copy(R&& r, O result, C comp = {}, Proj proj = {});
  }

  // reverse
  template<class BidirectionalIter>
    constexpr void reverse(BidirectionalIter first, BidirectionalIter last);
  template<class ExecutionPolicy, class BidirectionalIter>
    void reverse(ExecutionPolicy&& exec,
                 BidirectionalIter first, BidirectionalIter last);

  namespace ranges {
    template<bidirectional_iterator I, sentinel_for<I> S>
      requires permutable<I>
      constexpr I reverse(I first, S last);
    template<bidirectional_range R>
      requires permutable<iterator_t<R>>
      constexpr borrowed_iterator_t<R> reverse(R&& r);
  }

  template<class BidirectionalIter, class OutputIter>
    constexpr OutputIter reverse_copy(BidirectionalIter first, BidirectionalIter last,
                                      OutputIter result);
  template<class ExecutionPolicy, class BidirectionalIter, class ForwardIter>
    ForwardIter reverse_copy(ExecutionPolicy&& exec,
                             BidirectionalIter first, BidirectionalIter last,
                             ForwardIter result);

  namespace ranges {
    template<class I, class O>
      using reverse_copy_result = in_out_result<I, O>;

    template<bidirectional_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr reverse_copy_result<I, O>
        reverse_copy(I first, S last, O result);
    template<bidirectional_range R, weakly_incrementable O>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr reverse_copy_result<borrowed_iterator_t<R>, O>
        reverse_copy(R&& r, O result);
  }

  // rotate
  template<class ForwardIter>
    constexpr ForwardIter rotate(ForwardIter first, ForwardIter middle, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter rotate(ExecutionPolicy&& exec,
                       ForwardIter first, ForwardIter middle, ForwardIter last);

  namespace ranges {
    template<permutable I, sentinel_for<I> S>
      constexpr subrange<I> rotate(I first, I middle, S last);
    template<forward_range R>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle);
  }

  template<class ForwardIter, class OutputIter>
    constexpr OutputIter rotate_copy(ForwardIter first, ForwardIter middle,
                                     ForwardIter last, OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2 rotate_copy(ExecutionPolicy&& exec,
                             ForwardIter1 first, ForwardIter1 middle,
                             ForwardIter1 last, ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using rotate_copy_result = in_out_result<I, O>;

    template<forward_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr rotate_copy_result<I, O>
        rotate_copy(I first, I middle, S last, O result);
    template<forward_range R, weakly_incrementable O>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr rotate_copy_result<borrowed_iterator_t<R>, O>
        rotate_copy(R&& r, iterator_t<R> middle, O result);
  }

  // sample
  template<class PopulationIter, class SampleIter,
           class Distance, class UniformRandomBitGenerator>
    SampleIter sample(PopulationIter first, PopulationIter last,
                      SampleIter out, Distance n, UniformRandomBitGenerator&& g);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S,
             weakly_incrementable O, class Gen>
      requires (forward_iterator<I> || random_access_iterator<O>) &&
               indirectly_copyable<I, O> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g);
    template<input_range R, weakly_incrementable O, class Gen>
      requires (forward_range<R> || random_access_iterator<O>) &&
               indirectly_copyable<iterator_t<R>, O> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      O sample(R&& r, O out, range_difference_t<R> n, Gen&& g);
  }

  // shuffle
  template<class RandomAccessIter, class UniformRandomBitGenerator>
    void shuffle(RandomAccessIter first, RandomAccessIter last,
                 UniformRandomBitGenerator&& g);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Gen>
      requires permutable<I> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      I shuffle(I first, S last, Gen&& g);
    template<random_access_range R, class Gen>
      requires permutable<iterator_t<R>> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      borrowed_iterator_t<R> shuffle(R&& r, Gen&& g);
  }

  // shift
  template<class ForwardIter>
    constexpr ForwardIter
      shift_left(ForwardIter first, ForwardIter last,
                 typename iterator_traits<ForwardIter>::difference_type n);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter
      shift_left(ExecutionPolicy&& exec,
                 ForwardIter first, ForwardIter last,
                 typename iterator_traits<ForwardIter>::difference_type n);

  namespace ranges {
    template<permutable I, sentinel_for<I> S>
      constexpr subrange<I> shift_left(I first, S last, iter_difference_t<I> n);
    template<forward_range R>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> shift_left(R&& r, range_difference_t<R> n);
  }

  template<class ForwardIter>
    constexpr ForwardIter
      shift_right(ForwardIter first, ForwardIter last,
                  typename iterator_traits<ForwardIter>::difference_type n);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter
      shift_right(ExecutionPolicy&& exec,
                  ForwardIter first, ForwardIter last,
                  typename iterator_traits<ForwardIter>::difference_type n);

  namespace ranges {
    template<permutable I, sentinel_for<I> S>
      constexpr subrange<I> shift_right(I first, S last, iter_difference_t<I> n);
    template<forward_range R>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> shift_right(R&& r, range_difference_t<R> n);
  }

  // sorting and related operations
  // sorting
  template<class RandomAccessIter>
    constexpr void sort(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void sort(RandomAccessIter first, RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void sort(ExecutionPolicy&& exec,
              RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void sort(ExecutionPolicy&& exec,
              RandomAccessIter first, RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I sort(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R> sort(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    void stable_sort(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    void stable_sort(RandomAccessIter first, RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void stable_sort(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void stable_sort(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      I stable_sort(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      borrowed_iterator_t<R> stable_sort(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void partial_sort(RandomAccessIter first, RandomAccessIter middle,
                                RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void partial_sort(RandomAccessIter first, RandomAccessIter middle,
                                RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void partial_sort(ExecutionPolicy&& exec,
                      RandomAccessIter first, RandomAccessIter middle,
                      RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void partial_sort(ExecutionPolicy&& exec,
                      RandomAccessIter first, RandomAccessIter middle,
                      RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        partial_sort(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {});
  }

  template<class InputIter, class RandomAccessIter>
    constexpr RandomAccessIter
      partial_sort_copy(InputIter first, InputIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last);
  template<class InputIter, class RandomAccessIter, class Compare>
    constexpr RandomAccessIter
      partial_sort_copy(InputIter first, InputIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last, Compare comp);
  template<class ExecutionPolicy, class ForwardIter, class RandomAccessIter>
    RandomAccessIter
      partial_sort_copy(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last);
  template<class ExecutionPolicy, class ForwardIter, class RandomAccessIter,
           class Compare>
    RandomAccessIter
      partial_sort_copy(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last, Compare comp);

  namespace ranges {
    template<class I, class O>
      using partial_sort_copy_result = in_out_result<I, O>;

    template<input_iterator I1, sentinel_for<I1> S1,
             random_access_iterator I2, sentinel_for<I2> S2,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_copyable<I1, I2> && sortable<I2, Comp, Proj2> &&
               indirect_strict_weak_order<Comp, projected<I1, Proj1>,
                                          projected<I2, Proj2>>
      constexpr partial_sort_copy_result<I1, I2>
        partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
                          Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, random_access_range R2, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_copyable<iterator_t<R1>, iterator_t<R2>> &&
               sortable<iterator_t<R2>, Comp, Proj2> &&
               indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>,
                                          projected<iterator_t<R2>, Proj2>>
      constexpr partial_sort_copy_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
        partial_sort_copy(R1&& r, R2&& result_r, Comp comp = {},
                          Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class ForwardIter>
    constexpr bool is_sorted(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr bool is_sorted(ForwardIter first, ForwardIter last, Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    bool is_sorted(ExecutionPolicy&& exec,
                   ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    bool is_sorted(ExecutionPolicy&& exec,
                   ForwardIter first, ForwardIter last, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr bool is_sorted(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr bool is_sorted(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr ForwardIter is_sorted_until(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr ForwardIter is_sorted_until(ForwardIter first, ForwardIter last,
                                          Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter is_sorted_until(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    ForwardIter is_sorted_until(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last,
                                Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I is_sorted_until(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        is_sorted_until(R&& r, Comp comp = {}, Proj proj = {});
  }

  // Nth element
  template<class RandomAccessIter>
    constexpr void nth_element(RandomAccessIter first, RandomAccessIter nth,
                               RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void nth_element(RandomAccessIter first, RandomAccessIter nth,
                               RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void nth_element(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter nth,
                     RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void nth_element(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter nth,
                     RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        nth_element(I first, I nth, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        nth_element(R&& r, iterator_t<R> nth, Comp comp = {}, Proj proj = {});
  }

  // binary search
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr ForwardIter lower_bound(ForwardIter first, ForwardIter last,
                                      const T& value);
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
           class Compare>
    constexpr ForwardIter lower_bound(ForwardIter first, ForwardIter last,
                                      const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr I
          lower_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>,
             indirect_strict_weak_order
                 <const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr ForwardIter upper_bound(ForwardIter first, ForwardIter last,
                                      const T& value);
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
           class Compare>
    constexpr ForwardIter upper_bound(ForwardIter first, ForwardIter last,
                                      const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr I
          upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
    template<forward_range R, class T, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>,
             indirect_strict_weak_order
                 <const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr pair<ForwardIter, ForwardIter>
      equal_range(ForwardIter first, ForwardIter last, const T& value);
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
           class Compare>
    constexpr pair<ForwardIter, ForwardIter>
      equal_range(ForwardIter first, ForwardIter last, const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr subrange<I>
        equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>,
             indirect_strict_weak_order
                 <const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_subrange_t<R>
        equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
    constexpr bool binary_search(ForwardIter first, ForwardIter last,
                                 const T& value);
  template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
           class Compare>
    constexpr bool binary_search(ForwardIter first, ForwardIter last,
                                 const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             class T = projected_value_t<I, Proj>,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr bool binary_search(I first, S last, const T& value,
                                   Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             class T = projected_value_t<iterator_t<R>, Proj>,
             indirect_strict_weak_order
                 <const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr bool binary_search(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  // partitions
  template<class InputIter, class Pred>
    constexpr bool is_partitioned(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool is_partitioned(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool is_partitioned(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool is_partitioned(R&& r, Pred pred, Proj proj = {});
  }

  template<class ForwardIter, class Pred>
    constexpr ForwardIter partition(ForwardIter first, ForwardIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter partition(ExecutionPolicy&& exec,
                          ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr subrange<I> partition(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> partition(R&& r, Pred pred, Proj proj = {});
  }

  template<class BidirectionalIter, class Pred>
    BidirectionalIter stable_partition(BidirectionalIter first,
                                       BidirectionalIter last, Pred pred);
  template<class ExecutionPolicy, class BidirectionalIter, class Pred>
    BidirectionalIter stable_partition(ExecutionPolicy&& exec,
                                       BidirectionalIter first,
                                       BidirectionalIter last, Pred pred);

  namespace ranges {
    template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      requires permutable<I>
      subrange<I> stable_partition(I first, S last, Pred pred, Proj proj = {});
    template<bidirectional_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires permutable<iterator_t<R>>
      borrowed_subrange_t<R> stable_partition(R&& r, Pred pred, Proj proj = {});
  }

  template<class InputIter, class OutputIter1,
           class OutputIter2, class Pred>
    constexpr pair<OutputIter1, OutputIter2>
      partition_copy(InputIter first, InputIter last,
                     OutputIter1 out_true, OutputIter2 out_false, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class ForwardIter1,
           class ForwardIter2, class Pred>
    pair<ForwardIter1, ForwardIter2>
      partition_copy(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last,
                     ForwardIter1 out_true, ForwardIter2 out_false, Pred pred);

  namespace ranges {
    template<class I, class O1, class O2>
      using partition_copy_result = in_out_out_result<I, O1, O2>;

    template<input_iterator I, sentinel_for<I> S,
             weakly_incrementable O1, weakly_incrementable O2,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
      constexpr partition_copy_result<I, O1, O2>
        partition_copy(I first, S last, O1 out_true, O2 out_false,
                       Pred pred, Proj proj = {});
    template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
             class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O1> &&
               indirectly_copyable<iterator_t<R>, O2>
      constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
        partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {});
  }

  template<class ForwardIter, class Pred>
    constexpr ForwardIter
      partition_point(ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr I partition_point(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_iterator_t<R>
        partition_point(R&& r, Pred pred, Proj proj = {});
  }

  // merge
  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter merge(InputIter1 first1, InputIter1 last1,
                               InputIter2 first2, InputIter2 last2, OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter,
           class Compare>
    constexpr OutputIter merge(InputIter1 first1, InputIter1 last1,
                               InputIter2 first2, InputIter2 last2,
                               OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter merge(ExecutionPolicy&& exec,
                      ForwardIter1 first1, ForwardIter1 last1,
                      ForwardIter2 first2, ForwardIter2 last2, ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter merge(ExecutionPolicy&& exec,
                      ForwardIter1 first1, ForwardIter1 last1,
                      ForwardIter2 first2, ForwardIter2 last2,
                      ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using merge_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr merge_result<I1, I2, O>
        merge(I1 first1, S1 last1, I2 first2, S2 last2, O result,
              Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr merge_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
        merge(R1&& r1, R2&& r2, O result,
              Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class BidirectionalIter>
    void inplace_merge(BidirectionalIter first, BidirectionalIter middle,
                       BidirectionalIter last);
  template<class BidirectionalIter, class Compare>
    void inplace_merge(BidirectionalIter first, BidirectionalIter middle,
                       BidirectionalIter last, Compare comp);
  template<class ExecutionPolicy, class BidirectionalIter>
    void inplace_merge(ExecutionPolicy&& exec,
                       BidirectionalIter first, BidirectionalIter middle,
                       BidirectionalIter last);
  template<class ExecutionPolicy, class BidirectionalIter, class Compare>
    void inplace_merge(ExecutionPolicy&& exec,
                       BidirectionalIter first, BidirectionalIter middle,
                       BidirectionalIter last, Compare comp);

  namespace ranges {
    template<bidirectional_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      I inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {});
    template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      borrowed_iterator_t<R> inplace_merge(R&& r, iterator_t<R> middle,
                                           Comp comp = {}, Proj proj = {});
  }

  // set operations
  template<class InputIter1, class InputIter2>
    constexpr bool includes(InputIter1 first1, InputIter1 last1,
                            InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class Compare>
    constexpr bool includes(InputIter1 first1, InputIter1 last1,
                            InputIter2 first2, InputIter2 last2, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool includes(ExecutionPolicy&& exec,
                  ForwardIter1 first1, ForwardIter1 last1,
                  ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class Compare>
    bool includes(ExecutionPolicy&& exec,
                  ForwardIter1 first1, ForwardIter1 last1,
                  ForwardIter2 first2, ForwardIter2 last2, Compare comp);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
             indirect_strict_weak_order
                 <projected<I1, Proj1>, projected<I2, Proj2>> Comp = ranges::less>
      constexpr bool includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2,
             class Proj1 = identity, class Proj2 = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R1>, Proj1>,
                  projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
      constexpr bool includes(R1&& r1, R2&& r2, Comp comp = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter set_union(InputIter1 first1, InputIter1 last1,
                                   InputIter2 first2, InputIter2 last2,
                                   OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter set_union(InputIter1 first1, InputIter1 last1,
                                   InputIter2 first2, InputIter2 last2,
                                   OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter set_union(ExecutionPolicy&& exec,
                          ForwardIter1 first1, ForwardIter1 last1,
                          ForwardIter2 first2, ForwardIter2 last2,
                          ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter set_union(ExecutionPolicy&& exec,
                          ForwardIter1 first1, ForwardIter1 last1,
                          ForwardIter2 first2, ForwardIter2 last2,
                          ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using set_union_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_union_result<I1, I2, O>
        set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
                  Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
        set_union(R1&& r1, R2&& r2, O result, Comp comp = {},
                  Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter set_intersection(InputIter1 first1, InputIter1 last1,
                                          InputIter2 first2, InputIter2 last2,
                                          OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter set_intersection(InputIter1 first1, InputIter1 last1,
                                          InputIter2 first2, InputIter2 last2,
                                          OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter set_intersection(ExecutionPolicy&& exec,
                                 ForwardIter1 first1, ForwardIter1 last1,
                                 ForwardIter2 first2, ForwardIter2 last2,
                                 ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter set_intersection(ExecutionPolicy&& exec,
                                 ForwardIter1 first1, ForwardIter1 last1,
                                 ForwardIter2 first2, ForwardIter2 last2,
                                 ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using set_intersection_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_intersection_result<I1, I2, O>
        set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                         Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_intersection_result<borrowed_iterator_t<R1>,
                                        borrowed_iterator_t<R2>, O>
        set_intersection(R1&& r1, R2&& r2, O result,
                         Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter set_difference(InputIter1 first1, InputIter1 last1,
                                        InputIter2 first2, InputIter2 last2,
                                        OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter set_difference(InputIter1 first1, InputIter1 last1,
                                        InputIter2 first2, InputIter2 last2,
                                        OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter set_difference(ExecutionPolicy&& exec,
                               ForwardIter1 first1, ForwardIter1 last1,
                               ForwardIter2 first2, ForwardIter2 last2,
                               ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter set_difference(ExecutionPolicy&& exec,
                               ForwardIter1 first1, ForwardIter1 last1,
                               ForwardIter2 first2, ForwardIter2 last2,
                               ForwardIter result, Compare comp);

  namespace ranges {
    template<class I, class O>
      using set_difference_result = in_out_result<I, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_difference_result<I1, O>
        set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                       Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_difference_result<borrowed_iterator_t<R1>, O>
        set_difference(R1&& r1, R2&& r2, O result,
                       Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,
                                                  InputIter2 first2, InputIter2 last2,
                                                  OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,
                                                  InputIter2 first2, InputIter2 last2,
                                                  OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter set_symmetric_difference(ExecutionPolicy&& exec,
                                         ForwardIter1 first1, ForwardIter1 last1,
                                         ForwardIter2 first2, ForwardIter2 last2,
                                         ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter set_symmetric_difference(ExecutionPolicy&& exec,
                                         ForwardIter1 first1, ForwardIter1 last1,
                                         ForwardIter2 first2, ForwardIter2 last2,
                                         ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using set_symmetric_difference_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_symmetric_difference_result<I1, I2, O>
        set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                                 Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_symmetric_difference_result<borrowed_iterator_t<R1>,
                                                borrowed_iterator_t<R2>, O>
        set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // heap operations
  template<class RandomAccessIter>
    constexpr void push_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void push_heap(RandomAccessIter first, RandomAccessIter last,
                             Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I push_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R> push_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void pop_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void pop_heap(RandomAccessIter first, RandomAccessIter last,
                            Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I pop_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R> pop_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void make_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void make_heap(RandomAccessIter first, RandomAccessIter last,
                             Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I make_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R> make_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void sort_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void sort_heap(RandomAccessIter first, RandomAccessIter last,
                             Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S,
             class Comp = ranges::less, class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I sort_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R> sort_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr bool is_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr bool is_heap(RandomAccessIter first, RandomAccessIter last,
                           Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    bool is_heap(ExecutionPolicy&& exec,
                 RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    bool is_heap(ExecutionPolicy&& exec,
                 RandomAccessIter first, RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr bool is_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr bool is_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr RandomAccessIter
      is_heap_until(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr RandomAccessIter
      is_heap_until(RandomAccessIter first, RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    RandomAccessIter
      is_heap_until(ExecutionPolicy&& exec,
                    RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    RandomAccessIter
      is_heap_until(ExecutionPolicy&& exec,
                    RandomAccessIter first, RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I is_heap_until(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        is_heap_until(R&& r, Comp comp = {}, Proj proj = {});
  }

  // minimum and maximum
  template<class T> constexpr const T& min(const T& a, const T& b);
  template<class T, class Compare>
    constexpr const T& min(const T& a, const T& b, Compare comp);
  template<class T>
    constexpr T min(initializer_list<T> t);
  template<class T, class Compare>
    constexpr T min(initializer_list<T> t, Compare comp);

  namespace ranges {
    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {});
    template<copyable T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr T min(initializer_list<T> r, Comp comp = {}, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
      constexpr range_value_t<R> min(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class T> constexpr const T& max(const T& a, const T& b);
  template<class T, class Compare>
    constexpr const T& max(const T& a, const T& b, Compare comp);
  template<class T>
    constexpr T max(initializer_list<T> t);
  template<class T, class Compare>
    constexpr T max(initializer_list<T> t, Compare comp);

  namespace ranges {
    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {});
    template<copyable T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr T max(initializer_list<T> r, Comp comp = {}, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
      constexpr range_value_t<R> max(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class T> constexpr pair<const T&, const T&> minmax(const T& a, const T& b);
  template<class T, class Compare>
    constexpr pair<const T&, const T&> minmax(const T& a, const T& b, Compare comp);
  template<class T>
    constexpr pair<T, T> minmax(initializer_list<T> t);
  template<class T, class Compare>
    constexpr pair<T, T> minmax(initializer_list<T> t, Compare comp);

  namespace ranges {
    template<class T>
      using minmax_result = min_max_result<T>;

    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr minmax_result<const T&>
        minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {});
    template<copyable T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr minmax_result<T>
        minmax(initializer_list<T> r, Comp comp = {}, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
      constexpr minmax_result<range_value_t<R>>
        minmax(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr ForwardIter min_element(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr ForwardIter min_element(ForwardIter first, ForwardIter last,
                                      Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter min_element(ExecutionPolicy&& exec,
                            ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    ForwardIter min_element(ExecutionPolicy&& exec,
                            ForwardIter first, ForwardIter last,
                            Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        min_element(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr ForwardIter max_element(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr ForwardIter max_element(ForwardIter first, ForwardIter last,
                                      Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter max_element(ExecutionPolicy&& exec,
                            ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    ForwardIter max_element(ExecutionPolicy&& exec,
                            ForwardIter first, ForwardIter last,
                            Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I max_element(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        max_element(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr pair<ForwardIter, ForwardIter>
      minmax_element(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr pair<ForwardIter, ForwardIter>
      minmax_element(ForwardIter first, ForwardIter last, Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    pair<ForwardIter, ForwardIter>
      minmax_element(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    pair<ForwardIter, ForwardIter>
      minmax_element(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last, Compare comp);

  namespace ranges {
    template<class I>
      using minmax_element_result = min_max_result<I>;

    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr minmax_element_result<I>
        minmax_element(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr minmax_element_result<borrowed_iterator_t<R>>
        minmax_element(R&& r, Comp comp = {}, Proj proj = {});
  }

  // bounded value
  template<class T>
    constexpr const T& clamp(const T& v, const T& lo, const T& hi);
  template<class T, class Compare>
    constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp);

  namespace ranges {
    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr const T&
        clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});
  }

  // lexicographical comparison
  template<class InputIter1, class InputIter2>
    constexpr bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
                                           InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class Compare>
    constexpr bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
                                           InputIter2 first2, InputIter2 last2,
                                           Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool lexicographical_compare(ExecutionPolicy&& exec,
                                 ForwardIter1 first1, ForwardIter1 last1,
                                 ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Compare>
    bool lexicographical_compare(ExecutionPolicy&& exec,
                                 ForwardIter1 first1, ForwardIter1 last1,
                                 ForwardIter2 first2, ForwardIter2 last2,
                                 Compare comp);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
             sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
             indirect_strict_weak_order
                 <projected<I1, Proj1>, projected<I2, Proj2>> Comp = ranges::less>
      constexpr bool
        lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2,
                                Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Proj1 = identity,
             class Proj2 = identity,
             indirect_strict_weak_order
                 <projected<iterator_t<R1>, Proj1>,
                            projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
      constexpr bool
        lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {},
                                Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // three-way comparison algorithms
  template<class InputIter1, class InputIter2, class Cmp>
    constexpr auto lexicographical_compare_three_way(InputIter1 b1, InputIter1 e1,
                                                     InputIter2 b2, InputIter2 e2,
                                                     Cmp comp)
        -> decltype(comp(*b1, *b2));
  template<class InputIter1, class InputIter2>
    constexpr auto lexicographical_compare_three_way(InputIter1 b1, InputIter1 e1,
                                                     InputIter2 b2, InputIter2 e2);

  // permutations
  template<class BidirectionalIter>
    constexpr bool next_permutation(BidirectionalIter first,
                                    BidirectionalIter last);
  template<class BidirectionalIter, class Compare>
    constexpr bool next_permutation(BidirectionalIter first,
                                    BidirectionalIter last, Compare comp);

  namespace ranges {
    template<class I>
      using next_permutation_result = in_found_result<I>;

    template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr next_permutation_result<I>
        next_permutation(I first, S last, Comp comp = {}, Proj proj = {});
    template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr next_permutation_result<borrowed_iterator_t<R>>
        next_permutation(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class BidirectionalIter>
    constexpr bool prev_permutation(BidirectionalIter first,
                                    BidirectionalIter last);
  template<class BidirectionalIter, class Compare>
    constexpr bool prev_permutation(BidirectionalIter first,
                                    BidirectionalIter last, Compare comp);

  namespace ranges {
    template<class I>
      using prev_permutation_result = in_found_result<I>;

    template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr prev_permutation_result<I>
        prev_permutation(I first, S last, Comp comp = {}, Proj proj = {});
    template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr prev_permutation_result<borrowed_iterator_t<R>>
        prev_permutation(R&& r, Comp comp = {}, Proj proj = {});
  }
}
类模板 std::ranges::in_fun_result
namespace std::ranges {
  template<class I, class F>
  struct in_fun_result {
    [[no_unique_address]] I in;
    [[no_unique_address]] F fun;

    template<class I2, class F2>
      requires convertible_to<const I&, I2> && convertible_to<const F&, F2>
    constexpr operator in_fun_result<I2, F2>() const & {
      return {in, fun};
    }

    template<class I2, class F2>
      requires convertible_to<I, I2> && convertible_to<F, F2>
    constexpr operator in_fun_result<I2, F2>() && {
      return {std::move(in), std::move(fun)};
    }
  };
}
类模板 std::ranges::in_in_result
namespace std::ranges {
  template<class I1, class I2>
  struct in_in_result {
    [[no_unique_address]] I1 in1;
    [[no_unique_address]] I2 in2;

    template<class II1, class II2>
      requires convertible_to<const I1&, II1> && convertible_to<const I2&, II2>
    constexpr operator in_in_result<II1, II2>() const & {
      return {in1, in2};
    }

    template<class II1, class II2>
      requires convertible_to<I1, II1> && convertible_to<I2, II2>
    constexpr operator in_in_result<II1, II2>() && {
      return {std::move(in1), std::move(in2)};
    }
  };
}
类模板 std::ranges::in_out_result
namespace std::ranges {
  template<class I, class O>
  struct in_out_result {
    [[no_unique_address]] I in;
    [[no_unique_address]] O out;

    template<class I2, class O2>
      requires convertible_to<const I&, I2> && convertible_to<const O&, O2>
    constexpr operator in_out_result<I2, O2>() const & {
      return {in, out};
    }

    template<class I2, class O2>
      requires convertible_to<I, I2> && convertible_to<O, O2>
    constexpr operator in_out_result<I2, O2>() && {
      return {std::move(in), std::move(out)};
    }
  };
}
类模板 std::ranges::in_in_out_result
namespace std::ranges {
  template<class I1, class I2, class O>
  struct in_in_out_result {
    [[no_unique_address]] I1 in1;
    [[no_unique_address]] I2 in2;
    [[no_unique_address]] O  out;

    template<class II1, class II2, class OO>
      requires convertible_to<const I1&, II1> &&
               convertible_to<const I2&, II2> &&
               convertible_to<const O&, OO>
    constexpr operator in_in_out_result<II1, II2, OO>() const & {
      return {in1, in2, out};
    }

    template<class II1, class II2, class OO>
      requires convertible_to<I1, II1> &&
               convertible_to<I2, II2> &&
               convertible_to<O, OO>
    constexpr operator in_in_out_result<II1, II2, OO>() && {
      return {std::move(in1), std::move(in2), std::move(out)};
    }
  };
}
类模板 std::ranges::in_out_out_result
namespace std::ranges {
  template<class I, class O1, class O2>
  struct in_out_out_result {
    [[no_unique_address]] I  in;
    [[no_unique_address]] O1 out1;
    [[no_unique_address]] O2 out2;

    template<class II, class OO1, class OO2>
      requires convertible_to<const I&, II> &&
               convertible_to<const O1&, OO1> &&
               convertible_to<const O2&, OO2>
    constexpr operator in_out_out_result<II, OO1, OO2>() const & {
      return {in, out1, out2};
    }

    template<class II, class OO1, class OO2>
      requires convertible_to<I, II> &&
               convertible_to<O1, OO1> &&
               convertible_to<O2, OO2>
    constexpr operator in_out_out_result<II, OO1, OO2>() && {
      return {std::move(in), std::move(out1), std::move(out2)};
    }
  };
}
类模板 std::ranges::min_max_result
namespace std::ranges {
  template<class T>
  struct min_max_result {
    [[no_unique_address]] T min;
    [[no_unique_address]] T max;

    template<class T2>
      requires convertible_to<const T&, T2>
    constexpr operator min_max_result<T2>() const & {
      return {min, max};
    }

    template<class T2>
      requires convertible_to<T, T2>
    constexpr operator min_max_result<T2>() && {
      return {std::move(min), std::move(max)};
    }
  };
}
类模板 std::ranges::in_found_result
namespace std::ranges {
  template<class I>
  struct in_found_result {
    [[no_unique_address]] I in;
    bool found;

    template<class I2>
      requires convertible_to<const I&, I2>
    constexpr operator in_found_result<I2>() const & {
      return {in, found};
    }
    template<class I2>
      requires convertible_to<I, I2>
    constexpr operator in_found_result<I2>() && {
      return {std::move(in), found};
    }
  };
}
类模板 std::ranges::in_value_result
namespace std::ranges {
template<class I, class T>
  struct in_value_result {
    [[no_unique_address]] I in;
    [[no_unique_address]] T value;

    template<class I2, class T2>
      requires convertible_to<const I&, I2> && convertible_to<const T&, T2>
    constexpr operator in_value_result<I2, T2>() const & {
      return {in, value};
    }

    template<class I2, class T2>
      requires convertible_to<I, I2> && convertible_to<T, T2>
    constexpr operator in_value_result<I2, T2>() && {
      return {std::move(in), std::move(value)};
    }
  };
}
类模板 std::ranges::out_value_result
namespace std::ranges {
template<class O, class T>
  struct out_value_result {
    [[no_unique_address]] O out;
    [[no_unique_address]] T value;

    template<class O2, class T2>
      requires convertible_to<const O&, O2> && convertible_to<const T&, T2>
    constexpr operator out_value_result<O2, T2>() const & {
      return {out, value};
    }

    template<class O2, class T2>
      requires convertible_to<O, O2> && convertible_to<T, T2>
    constexpr operator out_value_result<O2, T2>() && {
      return {std::move(out), std::move(value)};
    }
  };
}

 C++ 标准库头文件 
此头文件是 numeric 库的一部分。

函数
iota

(C++11)

用起始值的连续增量填充一个范围
(函数模板)
ranges::iota

(C++23)

用起始值的连续增量填充一个范围
(算法函数对象)
accumulate

对元素范围求和或折叠
(函数模板)
reduce

(C++17)

类似于 std::accumulate,但顺序不定
(函数模板)
transform_reduce

(C++17)

应用一个可调用对象,然后以无序方式归约
(函数模板)
inner_product

计算两个元素范围的内积
(函数模板)
adjacent_difference

计算范围内相邻元素之间的差值
(函数模板)
partial_sum

计算元素范围的部分和
(函数模板)
inclusive_scan

(C++17)

类似于 std::partial_sum,在第 ith 个和中包含第 ith 个输入元素
(函数模板)
exclusive_scan

(C++17)

类似于 std::partial_sum,在第 ith 个和中排除第 ith 个输入元素
(函数模板)
transform_inclusive_scan

(C++17)

应用一个可调用对象,然后计算包含扫描
(函数模板)
transform_exclusive_scan

(C++17)

应用一个可调用对象,然后计算排除扫描
(函数模板)
gcd

(C++17)

计算两个整数的最大公约数
(函数模板)
lcm

(C++17)

计算两个整数的最小公倍数
(函数模板)
midpoint

(C++20)

两个数字或指针之间的中点
(函数模板)
add_sat

(C++26)

两个整数的饱和加法运算
(函数模板)
sub_sat

(C++26)

两个整数的饱和减法运算
(函数模板)
mul_sat

(C++26)

两个整数的饱和乘法运算
(函数模板)
div_sat

(C++26)

两个整数的饱和除法运算
(函数模板)
saturate_cast

(C++26)

返回一个整数值,该值被钳制到另一种整数类型的范围内
(函数模板)
概要
namespace std {
  // accumulate
  template<class InputIt, class T>
    constexpr T accumulate(InputIt first, InputIt last, T init);
  template<class InputIt, class T, class BinaryOperation>
    constexpr T accumulate(InputIt first, InputIt last, T init, BinaryOperation binary_op);

  // reduce
  template<class InputIt>
    constexpr typename iterator_traits<InputIt>::value_type
      reduce(InputIt first, InputIt last);
  template<class InputIt, class T>
    constexpr T reduce(InputIt first, InputIt last, T init);
  template<class InputIt, class T, class BinaryOperation>
    constexpr T reduce(InputIt first, InputIt last, T init, BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt>
    typename iterator_traits<ForwardIt>::value_type
      reduce(ExecutionPolicy&& exec,
             ForwardIt first, ForwardIt last);
  template<class ExecutionPolicy, class ForwardIt, class T>
    T reduce(ExecutionPolicy&& exec,
             ForwardIt first, ForwardIt last, T init);
  template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOperation>
    T reduce(ExecutionPolicy&& exec,
             ForwardIt first, ForwardIt last, T init, BinaryOperation binary_op);

  // inner product
  template<class InputIt1, class InputIt2, class T>
    constexpr T inner_product(InputIt1 first1, InputIt1 last1,
                              InputIt2 first2, T init);
  template<class InputIt1, class InputIt2, class T,
           class BinaryOperation1, class BinaryOperation2>
    constexpr T inner_product(InputIt1 first1, InputIt1 last1,
                              InputIt2 first2, T init,
                              BinaryOperation1 binary_op1,
                              BinaryOperation2 binary_op2);

  // transform reduce
  template<class InputIt1, class InputIt2, class T>
    constexpr T transform_reduce(InputIt1 first1, InputIt1 last1,
                                 InputIt2 first2,
                                 T init);
  template<class InputIt1, class InputIt2, class T,
           class BinaryOperation1, class BinaryOperation2>
    constexpr T transform_reduce(InputIt1 first1, InputIt1 last1,
                                 InputIt2 first2,
                                 T init,
                                 BinaryOperation1 binary_op1,
                                 BinaryOperation2 binary_op2);
  template<class InputIt, class T,
           class BinaryOperation, class UnaryOperation>
    constexpr T transform_reduce(InputIt first, InputIt last,
                                 T init,
                                 BinaryOperation binary_op, UnaryOperation unary_op);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2, class T>
    T transform_reduce(ExecutionPolicy&& exec,
                       ForwardIt1 first1, ForwardIt1 last1,
                       ForwardIt2 first2,
                       T init);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2, class T,
           class BinaryOperation1, class BinaryOperation2>
    T transform_reduce(ExecutionPolicy&& exec,
                       ForwardIt1 first1, ForwardIt1 last1,
                       ForwardIt2 first2,
                       T init,
                       BinaryOperation1 binary_op1,
                       BinaryOperation2 binary_op2);
  template<class ExecutionPolicy,
           class ForwardIt, class T,
           class BinaryOperation, class UnaryOperation>
    T transform_reduce(ExecutionPolicy&& exec,
                       ForwardIt first, ForwardIt last,
                       T init,
                       BinaryOperation binary_op, UnaryOperation unary_op);

  // partial sum
  template<class InputIt, class OutputIt>
    constexpr OutputIt partial_sum(InputIt first,
                                   InputIt last,
                                   OutputIt result);
  template<class InputIt, class OutputIt, class BinaryOperation>
    constexpr OutputIt partial_sum(InputIt first,
                                   InputIt last,
                                   OutputIt result,
                                   BinaryOperation binary_op);

  // exclusive scan
  template<class InputIt, class OutputIt, class T>
    constexpr OutputIt exclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      T init);
  template<class InputIt, class OutputIt, class T, class BinaryOperation>
    constexpr OutputIt exclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      T init, BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T>
    ForwardIt2 exclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              T init);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T,
           class BinaryOperation>
    ForwardIt2 exclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              T init, BinaryOperation binary_op);

  // inclusive scan
  template<class InputIt, class OutputIt>
    constexpr OutputIt inclusive_scan(InputIt first, InputIt last, OutputIt result);
  template<class InputIt, class OutputIt, class BinaryOperation>
    constexpr OutputIt inclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      BinaryOperation binary_op);
  template<class InputIt, class OutputIt, class BinaryOperation, class T>
    constexpr OutputIt inclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      BinaryOperation binary_op, T init);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
    ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
           class BinaryOperation>
    ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
           class BinaryOperation, class T>
    ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              BinaryOperation binary_op, T init);

  // transform exclusive scan
  template<class InputIt, class OutputIt, class T,
           class BinaryOperation, class UnaryOperation>
    constexpr OutputIt transform_exclusive_scan(InputIt first, InputIt last,
                                                OutputIt result,
                                                T init,
                                                BinaryOperation binary_op,
                                                UnaryOperation unary_op);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2, class T,
           class BinaryOperation, class UnaryOperation>
    ForwardIt2 transform_exclusive_scan(ExecutionPolicy&& exec,
                                        ForwardIt1 first, ForwardIt1 last,
                                        ForwardIt2 result,
                                        T init,
                                        BinaryOperation binary_op,
                                        UnaryOperation unary_op);

  // transform inclusive scan
  template<class InputIt, class OutputIt,
           class BinaryOperation, class UnaryOperation>
    constexpr OutputIt transform_inclusive_scan(InputIt first, InputIt last,
                                                OutputIt result,
                                                BinaryOperation binary_op,
                                                UnaryOperation unary_op);
  template<class InputIt, class OutputIt,
           class BinaryOperation, class UnaryOperation, class T>
    constexpr OutputIt transform_inclusive_scan(InputIt first, InputIt last,
                                                OutputIt result,
                                                BinaryOperation binary_op,
                                                UnaryOperation unary_op,
                                                T init);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2,
           class BinaryOperation, class UnaryOperation>
    ForwardIt2 transform_inclusive_scan(ExecutionPolicy&& exec,
                                        ForwardIt1 first, ForwardIt1 last,
                                        ForwardIt2 result,
                                        BinaryOperation binary_op,
                                        UnaryOperation unary_op);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2,
           class BinaryOperation, class UnaryOperation, class T>
    ForwardIt2 transform_inclusive_scan(ExecutionPolicy&& exec,
                                        ForwardIt1 first, ForwardIt1 last,
                                        ForwardIt2 result,
                                        BinaryOperation binary_op,
                                        UnaryOperation unary_op,
                                        T init);

  // adjacent difference
  template<class InputIt, class OutputIt>
    constexpr OutputIt adjacent_difference(InputIt first, InputIt last,
                                           OutputIt result);
  template<class InputIt, class OutputIt, class BinaryOperation>
    constexpr OutputIt adjacent_difference(InputIt first, InputIt last,
                                           OutputIt result,
                                           BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
    ForwardIt2 adjacent_difference(ExecutionPolicy&& exec,
                                   ForwardIt1 first, ForwardIt1 last,
                                   ForwardIt2 result);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
           class BinaryOperation>
    ForwardIt2 adjacent_difference(ExecutionPolicy&& exec,
                                   ForwardIt1 first, ForwardIt1 last,
                                   ForwardIt2 result,
                                   BinaryOperation binary_op);

  // iota
  template<class ForwardIt, class T>
    constexpr void iota(ForwardIt first, ForwardIt last, T value);

  namespace ranges {
    template<class O, class T>
      using iota_result = out_value_result<O, T>;

    template<input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
      requires indirectly_writable<O, const T&>
      constexpr iota_result<O, T> iota(O first, S last, T value);

    template<weakly_incrementable T, output_range<const T&> R>
      constexpr iota_result<borrowed_iterator_t<R>, T> iota(R&& r, T value);
  }

  // greatest common divisor
  template<class M, class N>
    constexpr common_type_t<M, N> gcd(M m, N n);

  // least common multiple
  template<class M, class N>
    constexpr common_type_t<M, N> lcm(M m, N n);

  // midpoint
  template<class T>
    constexpr T midpoint(T a, T b) noexcept;
  template<class T>
    constexpr T* midpoint(T* a, T* b);

  // saturation arithmetic
  template<class T>
    constexpr T add_sat(T x, T y) noexcept;           // freestanding
  template<class T>
    constexpr T sub_sat(T x, T y) noexcept;           // freestanding
  template<class T>
    constexpr T mul_sat(T x, T y) noexcept;           // freestanding
  template<class T>
    constexpr T div_sat(T x, T y) noexcept;           // freestanding
  template<class T, class U>
    constexpr T saturate_cast(U x) noexcept;          // freestanding
}

双倍经验

共 20 篇博客