zoukankan      html  css  js  c++  java
  • 我的代码模板(持更)

    GitHub README.md 无法加载 MathJax 数学公式,可以通过安装浏览器插件解决。

    IO 及其他

    快速读写

    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    

    关闭同步流

    ios::sync_with_stdio(false);
    

    文件重定向

    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    

    随机数

    default_random_engine generator { random_device {} () };
    shuffle(nums.begin(), nums.end(), generator);
    

    运行时间

    clock_t start, end;
    start = clock();
    // TODO
    end = clock();
    cout << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
    

    Lambda

    auto cmp = [](int a, int b) -> bool { return a > b; };
    priority_queue<int, vector<int>, decltype(cmp)> q(cmp);
    

    万能头文件

    // C++ includes used for precompiling -*- C++ -*-
     
    // Copyright (C) 2003-2014 Free Software Foundation, Inc.
    //
    // This file is part of the GNU ISO C++ Library.  This library is free
    // software; you can redistribute it and/or modify it under the
    // terms of the GNU General Public License as published by the
    // Free Software Foundation; either version 3, or (at your option)
    // any later version.
     
    // This 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.
     
    // Under Section 7 of GPL version 3, you are granted additional
    // permissions described in the GCC Runtime Library Exception, version
    // 3.1, as published by the Free Software Foundation.
     
    // You should have received a copy of the GNU General Public License and
    // a copy of the GCC Runtime Library Exception along with this program;
    // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    // <http://www.gnu.org/licenses/>.
     
    /** @file stdc++.h
     *  This is an implementation file for a precompiled header.
     */
     
    // 17.4.1.2 Headers
     
    // C
    #ifndef _GLIBCXX_NO_ASSERT
    #include <cassert>
    #endif
    #include <cctype>
    #include <cerrno>
    #include <cfloat>
    #include <ciso646>
    #include <climits>
    #include <clocale>
    #include <cmath>
    #include <csetjmp>
    #include <csignal>
    #include <cstdarg>
    #include <cstddef>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
     
    #if __cplusplus >= 201103L
    #include <ccomplex>
    #include <cfenv>
    #include <cinttypes>
    #include <cstdbool>
    #include <cstdint>
    #include <ctgmath>
    #include <cwchar>
    #include <cwctype>
    #endif
     
    // C++
    #include <algorithm>
    #include <bitset>
    #include <complex>
    #include <deque>
    #include <exception>
    #include <fstream>
    #include <functional>
    #include <iomanip>
    #include <ios>
    #include <iosfwd>
    #include <iostream>
    #include <istream>
    #include <iterator>
    #include <limits>
    #include <list>
    #include <locale>
    #include <map>
    #include <memory>
    #include <new>
    #include <numeric>
    #include <ostream>
    #include <queue>
    #include <set>
    #include <sstream>
    #include <stack>
    #include <stdexcept>
    #include <streambuf>
    #include <string>
    #include <typeinfo>
    #include <utility>
    #include <valarray>
    #include <vector>
     
    #if __cplusplus >= 201103L
    #include <array>
    #include <atomic>
    #include <chrono>
    #include <condition_variable>
    #include <forward_list>
    #include <future>
    #include <initializer_list>
    #include <mutex>
    #include <random>
    #include <ratio>
    #include <regex>
    #include <scoped_allocator>
    #include <system_error>
    #include <thread>
    #include <tuple>
    #include <typeindex>
    #include <type_traits>
    #include <unordered_map>
    #include <unordered_set>
    #endif
    

    字符串

    字符串分割

    vector<string> split(const string& s, const string& sep)
    {
        vector<string> res;
        string::size_type pos1, pos2;
        pos2 = s.find(sep);
        pos1 = 0;
        while (string::npos != pos2) {
            res.push_back(s.substr(pos1, pos2 - pos1));
            pos1 = pos2 + sep.size();
            pos2 = s.find(sep, pos1);
        }
        if (pos1 != s.length()) {
            res.push_back(s.substr(pos1));
        }
        return res;
    }
    

    KMP 算法

    void getNext(char* p)
    {
        int len = (int)strlen(p + 1);
        for (int i = 2, j = 0; i <= len; i++) {
            while (j && p[i] != p[j + 1]) j = nxt[j];
            if (p[i] == p[j + 1]) j++;
            nxt[i] = j;
        }
    }
    
    void kmp(char* s, char* p)
    {
        int slen = (int)strlen(s + 1), plen = (int)strlen(p + 1);
        for (int i = 1, j = 0; i <= slen; i++) {
            while (j && s[i] != p[j + 1]) j = nxt[j];
            if (s[i] == p[j + 1]) j++;
            if (j == plen) {
                printf("%d
    ", i - plen + 1);
                j = nxt[j];
            }
        }
    }
    

    Manacher 算法

    LeetCode 5 Longest Palindromic Substring

    class Solution {
    public:
        string longestPalindrome(string s)
        {
            int len = (int)s.length();
            int n = len * 2 + 2;
            vector<int> mp(n, 0);
            string ma("$#");
            for (int i = 0; i < len; ++i) {
                ma.push_back(s[i]);
                ma.push_back('#');
            }
            int mx = 0, id = 0, p = 0;
            for (int i = 0; i < n; ++i) {
                mp[i] = mx > i ? min(mx - i, mp[id * 2 - i]) : 1;
                if (i == 0) continue;
                while (ma[i + mp[i]] == ma[i - mp[i]]) {
                    ++mp[i];
                }
                if (mx < mp[i] + i) {
                    mx = mp[i] + i;
                    id = i;
                }
                if (mp[i] > mp[p]) {
                    p = i;
                }
            }
            len = mp[p] - 1;
            p = (p - len) / 2;
            return s.substr(p, len);
        }
    };
    

    洛谷 P3805 【模板】manacher算法

    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxn = 11e6 + 10;
    int mp[maxn << 1];
    char s[maxn], ma[maxn << 1];
    
    void manacher(int len)
    {
        memset(mp, 0, sizeof mp);
        int l = 0;
        ma[l++] = '$';
        ma[l++] = '#';
        for (int i = 0; i < len; ++i) {
            ma[l++] = s[i];
            ma[l++] = '#';
        }
        ma[l] = '';
        int mx = 0, id = 0;
        for (int i = 0; i < l; ++i) {
            mp[i] = mx > i ? min(mx - i, mp[id * 2 - i]) : 1;
            while (ma[i + mp[i]] == ma[i - mp[i]]) ++mp[i];
            if (mx < mp[i] + i) {
                mx = mp[i] + i;
                id = i;
            }
        }
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        scanf("%s", s);
        int len = (int)strlen(s);
        manacher(len);
        int res = 0;
        for (int i = 0; i < len * 2 + 2; ++i) {
            res = max(res, mp[i] - 1);
        }
        printf("%d
    ", res);
        return 0;
    }
    

    AC 自动机

    洛谷 P3808 【模板】AC自动机(简单版)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e6 + 10);
    char s[maxn];
    int idx, trie[maxn][26];
    int ext[maxn], fail[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void insert(char* str)
    {
        int u = 0;
        for (int i = 0; str[i]; ++i) {
            int c = str[i] - 'a';
            if (not trie[u][c]) {
                trie[u][c] = ++idx;
            }
            u = trie[u][c];
        }
        ++ext[u];
    }
    
    void build()
    {
        queue<int> q;
        for (int i = 0; i < 26; ++i) {
            if (trie[0][i]) {
                q.push(trie[0][i]);
            }
        }
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < 26; ++i) {
                int& v = trie[u][i];
                if (v) {
                    fail[v] = trie[fail[u]][i];
                    q.push(v);
                } else {
                    v = trie[fail[u]][i];
                }
            }
        }
    }
    
    int query(char* str)
    {
        int u = 0, res = 0;
        for (int i = 0; str[i]; ++i) {
            int c = str[i] - 'a';
            u = trie[u][c];
            for (int j = u; j and compl ext[j]; j = fail[j]) {
                res += ext[j];
                ext[j] = -1;
            }
        }
        return res;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        int n = read();
        for (int i = 0; i < n; ++i) {
            scanf("%s", s);
            insert(s);
        }
        build();
        scanf("%s", s);
        write(query(s), true);
        return 0;
    }
    

    洛谷 P3796 【模板】AC自动机(加强版)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(160);
    const int maxl(1e6 + 10);
    const int maxs(maxn * 80);
    char s[maxn][maxn], t[maxl];
    int tot, trie[maxs][26];
    int idx[maxs], fail[maxs], cnt[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void init()
    {
        tot = 0;
        memset(trie, 0, sizeof(trie));
        memset(fail, 0, sizeof(fail));
        memset(idx, 0, sizeof idx);
        memset(cnt, 0, sizeof cnt);
    }
    
    void insert(char* str, int id)
    {
        int u = 0;
        for (int i = 1; str[i]; ++i) {
            int c = str[i] - 'a';
            if (not trie[u][c]) {
                trie[u][c] = ++tot;
            }
            u = trie[u][c];
        }
        idx[u] = id;
    }
    
    void build()
    {
        queue<int> q;
        for (int i = 0; i < 26; ++i) {
            if (trie[0][i]) {
                q.push(trie[0][i]);
            }
        }
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < 26; ++i) {
                int& v = trie[u][i];
                if (v) {
                    fail[v] = trie[fail[u]][i];
                    q.push(v);
                } else {
                    v = trie[fail[u]][i];
                }
            }
        }
    }
    
    int query(char* str, int n)
    {
        int u = 0, res = 0;
        for (int i = 1; str[i]; ++i) {
            int c = str[i] - 'a';
            u = trie[u][c];
            for (int j = u; j; j = fail[j]) {
                ++cnt[idx[j]];
            }
        }
        for (int i = 1; i <= n; ++i) {
            res = max(res, cnt[i]);
        }
        return res;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        int n;
        while (compl scanf("%d", bitand n) and n) {
            init();
            for (int i = 1; i <= n; ++i) {
                scanf("%s", s[i] + 1);
                insert(s[i], i);
            }
            build();
            scanf("%s", t + 1);
            int res = query(t, n);
            write(res, true);
            for (int i = 1; i <= n; ++i) {
                if (cnt[i] == res) {
                    puts(s[i] + 1);
                }
            }
        }
        return 0;
    }
    

    高精度

    #define MAXLEN 10010
    #define MAXN 9999
    #define MAXSIZE 1010
    #define DLEN 4
     
    class BigNum
    {
    private:
        int a[MAXLEN];
        int len;
    public:
        BigNum() { len = 1; memset(a, 0, sizeof(a)); }
        BigNum(const int);
        BigNum(const char*);
        BigNum(const BigNum&);
        BigNum& operator =(const BigNum &);
        friend istream& operator >>(istream&, BigNum&);
        friend ostream& operator <<(ostream&, BigNum&);
        BigNum operator +(const BigNum&) const;
        BigNum operator -(const BigNum&) const;
        BigNum operator *(const BigNum&) const;
        BigNum operator /(const int&) const;
        BigNum operator ^(const int&) const;
        int operator %(const int&) const;
        bool operator >(const BigNum& T)const;
        bool operator >(const int& t)const;
        void print();
    };
     
    BigNum::BigNum(const int b)
    {
        int c, d = b;
        len = 0;
        memset(a, 0, sizeof(a));
        while (d > MAXN)
        {
            c = d - (d / (MAXN + 1)) * (MAXN + 1);
            d = d / (MAXN + 1);
            a[len++] = c;
        }
        a[len++] = d;
    }
     
    BigNum::BigNum(const char* s)
    {
        int t, k, index, L, i;
        memset(a, 0, sizeof(a));
        L = (int)strlen(s);
        len = L / DLEN;
        if (L % DLEN) len++;
        index = 0;
        for (i = L - 1; i >= 0; i -= DLEN)
        {
            t = 0;
            k = i - DLEN + 1;
            if (k < 0) k = 0;
            for (int j = k; j <= i; j++)
                t = t * 10 + s[j] - '0';
            a[index++] = t;
        }
    }
     
    BigNum::BigNum(const BigNum& T) : len(T.len)
    {
        int i;
        memset(a, 0, sizeof(a));
        for (i = 0; i < len; i++) a[i] = T.a[i];
    }
     
    BigNum& BigNum::operator =(const BigNum& n)
    {
        int i;
        len = n.len;
        memset(a, 0, sizeof(a));
        for (i = 0; i < len; i++) a[i] = n.a[i];
        return *this;
    }
     
    istream& operator >>(istream& in, BigNum& b)
    {
        char ch[MAXSIZE * 4];
        int i = -1;
        in >> ch;
        int L = (int)strlen(ch);
        int count = 0, sum = 0;
        for (i = L - 1; i >= 0;)
        {
            sum = 0;
            int t = 1;
            for (int j = 0; j < 4 && i >= 0; j++, i--, t *= 10)
                sum += (ch[i] - '0') * t;
            b.a[count] = sum;
            count++;
        }
        b.len = count++;
        return in;
    }
     
    ostream& operator <<(ostream& out, BigNum& b)
    {
        int i;
        cout << b.a[b.len - 1];
        for (i = b.len - 2; i >= 0; i--)
            printf("%04d", b.a[i]);
        return out;
    }
        
    BigNum BigNum::operator +(const BigNum& T) const
    {
        BigNum t(*this);
        int i, big;
        big = T.len > len ? T.len : len;
        for (i = 0; i < big; i++)
        {
            t.a[i] += T.a[i];
            if (t.a[i] > MAXN)
            {
                t.a[i + 1]++;
                t.a[i] -= MAXN + 1;
            }
        }
        if (t.a[big] != 0) t.len = big + 1;
        else t.len = big;
        return t;
    }
     
    BigNum BigNum::operator -(const BigNum& T) const
    {
        int i, j, big;
        bool flag;
        BigNum t1, t2;
        if (*this > T)
        {
            t1 = *this;
            t2 = T;
            flag = 0;
        }
        else
        {
            t1 = T;
            t2 = *this;
            flag = 1;
        }
        big = t1.len;
        for (i = 0; i < big; i++)
        {
            if (t1.a[i] < t2.a[i])
            {
                j = i + 1;
                while (t1.a[j] == 0) j++;
                t1.a[j--]--;
                while (j > i) t1.a[j--] += MAXN;
                t1.a[i] += MAXN + 1 - t2.a[i];
            }
            else t1.a[i] -= t2.a[i];
        }
        t1.len = big;
        while (t1.a[t1.len - 1] == 0 && t1.len > 1)
        {
            t1.len--;
            big--;
        }
        if (flag) t1.a[big - 1] = 0 - t1.a[big - 1];
        return t1;
    }
     
    BigNum BigNum::operator *(const BigNum& T)const
    {
        BigNum ret;
        int i, j = 0, up;
        int temp, temp1;
        for (i = 0; i < len; i++)
        {
            up = 0;
            for (j = 0; j < T.len; j++)
            {
                temp = a[i] * T.a[j] + ret.a[i + j] + up;
                if (temp > MAXN)
                {
                    temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);
                    up = temp / (MAXN + 1);
                    ret.a[i + j] = temp1;
                }
                else
                {
                    up = 0;
                    ret.a[i + j] = temp;
                }
            }
            if (up != 0) ret.a[i + j] = up;
        }
        ret.len = i + j;
        while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
        return ret;
    }
     
    BigNum BigNum::operator /(const int& b)const
    {
        BigNum ret;
        int i, down = 0;
        for (i = len - 1; i >= 0; i--)
        {
            ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
            down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
        }
        ret.len = len;
        while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
        return ret;
    }
     
    int BigNum::operator %(const int& b) const
    {
        int i, d = 0;
        for (i = len - 1; i >= 0; i--)
            d = ((d * (MAXN + 1)) % b + a[i]) % b;
        return d;
    }
     
    BigNum BigNum::operator ^(const int& n) const
    {
        BigNum t, ret(1);
        int i;
        if (n < 0) exit(-1);
        if (n == 0) return 1;
        if (n == 1) return *this;
        int m = n;
        while (m > 1)
        {
            t = *this;
            for (i = 1; (i << 1) <= m; i <<= 1) t = t * t;
            m -= i;
            ret = ret * t;
            if (m == 1) ret = ret * (*this);
        }
        return ret;
    }
     
    bool BigNum::operator >(const BigNum& T) const
    {
        int ln;
        if (len > T.len) return true;
        else if (len == T.len)
        {
            ln = len - 1;
            while (a[ln] == T.a[ln] && ln >= 0) ln--;
            if (ln >= 0 && a[ln] > T.a[ln]) return true;
            else return false;
        }
        else return false;
    }
     
    bool BigNum::operator >(const int& t) const
    {
        BigNum b(t);
        return *this > b;
    }
     
    void BigNum::print()
    {
        int i;
        printf("%d", a[len - 1]);
        for (i = len - 2; i >= 0; i--)
            printf("%04d", a[i]);
        printf("
    ");
    }
    

    数学

    快速幂

    ll qpow(ll x, ll k)
    {
        ll res = 1;
        while (k) {
            if (k & 1) {
                res = res * x % mod;
            }
            x = x * x % mod;
            k >>= 1;
        }
        return res;
    }
    

    矩阵快速幂

    洛谷 P3390 【模板】矩阵快速幂

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int mod(1e9 + 7);
    const int maxn(1e2 + 10);
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    struct matrix {
        int n;
        ll val[maxn][maxn];
        
        matrix(vector<vector<int>> vec)
        {
            assert(vec.size() == vec.front().size());
            this->n = (int)vec.size();
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    val[i][j] = vec[i][j];
                }
            }
        }
        
        matrix(int n, bool id = false)
        {
            this->n = n;
            memset(val, 0, sizeof val);
            if (not id) return;
            // identity matrix
            for (int i = 0; i < n; ++i) {
                val[i][i] = id;
            }
        }
        
        matrix operator *(const matrix& rhs) {
            assert(n == rhs.n);
            matrix res(n);
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    for (int k = 0; k < n; ++k) {
                        res.val[i][j] = (res.val[i][j] + val[i][k] * rhs.val[k][j] % mod) % mod;
                    }
                }
            }
            return res;
        };
        
        matrix operator ^(ll k)
        {
            matrix res(n, true), x = *this;
            while (k) {
                if (k bitand 1) {
                    res = res * x;
                }
                x = x * x;
                k >>= 1;
            }
            return res;
        }
    };
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        int n = read();
        ll k = read<ll>();
        matrix mat(n);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                mat.val[i][j] = read();
            }
        }
        mat = mat ^ k;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                write(mat.val[i][j], j == n - 1 ? '
    ' : ' ');
            }
        }
        return 0;
    }
    

    筛法

    欧拉筛法
    void euler(int n, vector<int>& primes)
    {
        primes.clear();
        vector<bool> isPrime(n + 1, true);
        isPrime[0] = isPrime[1] = false;
        for (int i = 2; i <= n; i++) {
            if (isPrime[i]) {
                primes.push_back(i);
            }
            for (int p : primes) {
                if (1ll * i * p > n) break;
                isPrime[i * p] = false;
                if (i % p == 0) break;
            }
        }
    }
    

    埃拉托斯特尼筛法

    void eratosthenes(int n, vector<int>& primes)
    {
        primes.clear();
        vector<bool> isPrime(n + 1, true);
        isPrime[0] = isPrime[1] = false;
        for (int i = 2; i <= n; i++) {
            if (!isPrime[i]) continue;
            primes.push_back(i);
            if (ll(i) * i > n) continue;
            for (int j = i * i; j <= n; j += i) {
                isPrime[j] = false;
            }
        }
    }
    

    欧拉函数

    欧拉函数

    欧拉函数(Euler's totient function),即 (varphi(n)) ,表示的是小于等于 (n)(n) 互质的数的个数。

    比如说 (varphi(1) = 1)

    (n) 是质数的时候,显然有 (varphi(n) = n - 1)

    利用唯一分解定理,我们可以把一个整数唯一地分解为质数幂次的乘积。

    (n = prod_{i=1}^{n}p_i^{k_i}),其中 (p_i) 是质数,那么 (varphi(n) = n imes prod_{i = 1}^s{dfrac{p_i - 1}{p_i}})

    欧拉定理

    (gcd(a, m) = 1) ,则(a^{varphi(m)} equiv 1 pmod{m})

    费马小定理

    (p) 为素数, (gcd(a, p) = 1) ,则 (a^{p - 1} equiv 1 pmod{p})

    威尔逊定理

    ((p-1)!equiv-1pmod{p})

    (p) 为质数,则 (p) 可整除 ((p-1)!+1)

    筛法求欧拉函数
    void phi_table()
    {
        for (int i = 1; i < maxn; i++) {
            phi[i] = i;
        }
        for (int i = 2; i < maxn; i++) {
            if (phi[i] == i) {
                for (int j = i; j < maxn; j += i) {
                    phi[j] = phi[j] / i * (i - 1);
                }
            }
        }
    }
    
    Pollard Rho 算法求欧拉函数
    ll get_phi(int n)
    {
        ll res = 1;
        for (int i = 2; i <= sqrt(n); i++) {
            if (n % i == 0) {
                n /= i;
                res *= i - 1;
                while (n % i == 0) {
                    n /= i;
                    res *= i;
                }
            }
        }
        if (n > 1) {
            res *= n - 1;
        }
        return res;
    }
    

    Polya 定理

    (m) 颗珠子,(n) 种颜色: (L=dfrac{1}{m}cdot sum ^{m}_{i=1}n^{gcd left( i,m ight) })

    (n=m)(L=dfrac{1}{n}sum _{p|n}(varphileft(p ight)cdot n^{dfrac{n}{p}})=sum _{p|n}(varphileft(p ight)cdot n^{dfrac{n}{p}-1}))

    逆元

    扩展欧几里得法求逆元
    void exgcd(int a, int b, int& x, int& y)
    {
        if (b == 0) {
            x = 1;
            y = 0;
            return;
        }
        exgcd(b, a % b, y, x);
        y -= a / b * x;
    }
    
    快速幂法求逆元

    因为 (ax equiv 1 pmod b)

    所以 (ax equiv a^{b-1} pmod b)(根据 费马小定理 );

    所以 (x equiv a^{b-2} pmod b)

    线性求逆元

    求出 (1,2,...,n) 中每个数关于 (p) 的逆元。

    首先,很显然的 (1^{-1} equiv 1 pmod p)

    然后,设 (p=ki+j,j<i,1<i<p) ,再放到 (mod p) 意义下就会得到:(ki+j equiv 0 pmod p)

    两边同时乘 (i^{-1},j^{-1})

    (kj^{-1}+i^{-1} equiv 0 pmod p)

    (i^{-1} equiv -kj^{-1} pmod p)

    (i^{-1} equiv -(frac{p}{i}) (p mod i)^{-1})

    inv[i] = 1;
    for (int i = 2; i <= n; i++) {
        inv[i] = (ll)(p - p / i) * inv[p % i] % p;
    }
    

    组合数

    Pascal 公式打表组合数取模
    const int maxn = 1e3 + 5;
    const int mod = 1e5 + 3;
    int tC[maxn][maxn];
    
    inline int C(int n, int k)
    {
        if (k > n) return 0;
        return tC[n][k];
    }
    
    void calcC(int n)
    {
        for (int i = 0; i < n; i++) {
            tC[i][0] = 1;
            for (int j = 1; j < i; j++) {
                tC[i][j] = (C(i - 1, j - 1) + C(i - 1, j)) % mod;
            }
            tC[i][i] = 1;
        }
    }
    
    const int maxn = 1e3 + 5;
    const int mod = 1e5 + 3;
    int tC[maxn * maxn];
    
    inline int loc(int n, int k)
    {
        int pos = (1 + (n >> 1)) * (n >> 1);
        pos += k;
        pos += (n & 1) ? (n + 1) >> 1 : 0;
        return pos;
    }
    
    inline int C(int n, int k)
    {
        if (k > n) return 0;
        k = min(n - k, k);
        return tC[loc(n, k)];
    }
    
    void calcC(int n)
    {
        for (int i = 0; i < n; i++) {
            tC[loc(i, 0)] = 1;
            for (int j = 1, e = i >> 1; j <= e; j++) {
                tC[loc(i, j)] = C(i - 1, j) + C(i - 1, j - 1);
            }
        }
    }
    

    图论

    Dijkstra 算法

    洛谷 P4779 【模板】单源最短路径(标准版)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const ll _inf(0x3f3f3f3f3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(1e5 + 10);
    const int maxm(2e5 + 10);
    int ecnt, head[maxn];
    ll dis[maxn];
    bool vis[maxn];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void dijkstra(int src)
    {
        priority_queue<p, vector<p>, greater<p>> q;
        q.push(p(0, src));
        dis[src] = 0;
        while (not q.empty()) {
            int u = q.top().second;
            q.pop();
            if (vis[u]) continue;
            vis[u] = true;
            for (int i = head[u]; ~i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    q.push(p(dis[v], v));
                }
            }
        }
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        memset(dis, 0x3f, sizeof dis);
        int n = read(), m = read(), s = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
        }
        dijkstra(s);
        for (int i = 1; i <= n; ++i) {
            write(dis[i] == _inf ? INT_MAX : dis[i], i == n ? '
    ' : ' ');
        }
        return 0;
    }
    

    SPFA 算法

    洛谷 P3371 【模板】单源最短路径(弱化版)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const ll _inf(0x3f3f3f3f3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(1e4 + 10);
    const int maxm(5e5 + 10);
    int ecnt, head[maxn];
    ll dis[maxn];
    bool vis[maxn];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void spfa(int src)
    {
        queue<int> q;
        q.push(src);
        dis[src] = 0;
        vis[src] = true;
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for (int i = head[u]; ~i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if (not vis[v]) {
                        q.push(v);
                        vis[v] = true;
                    }
                }
            }
        }
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        memset(dis, 0x3f, sizeof dis);
        int n = read(), m = read(), s = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
        }
        spfa(s);
        for (int i = 1; i <= n; ++i) {
            write(dis[i] == _inf ? INT_MAX : dis[i], i == n ? '
    ' : ' ');
        }
        return 0;
    }
    

    玄学优化 https://www.luogu.com.cn/blog/xhhkwy/spfa-hacker-orzorz

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(1e5 + 10);
    const int maxm(1e6 + 10);
    int ecnt, head[maxn];
    int dis[maxn];
    bool vis[maxn];
    deque<int> q;
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void swap_slf()
    {
        if (q.size() > 2 and dis[q.front()] > dis[q.back()]) {
            swap(q.front(), q.back());
        }
    }
    
    void spfa(int src)
    {
        dis[src] = 0;
        q.push_back(src);
        vis[src] = true;
        while (not q.empty()) {
            int u = q.front();
            q.pop_front();
            swap_slf();
            vis[u] = false;
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if (not vis[v]) {
                        q.push_back(v);
                        swap_slf();
                        vis[v] = true;
                    }
                }
            }
        }
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        memset(dis, 0x3f, sizeof dis);
        int n = read(), m = read(), s = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
        }
        spfa(s);
        for (int i = 1; i <= n; ++i) {
            if (dis[i] == inf) {
                puts("NO PATH");
            } else {
                write(dis[i], i == n ? 10 : 32);
            }
        }
        return 0;
    }
    

    洛谷 P3385 【模板】负环

    判断存在负环的条件:1、当前点入列达到 (n) 次;2、源点到当前点的最短(长)路径达到 (n)

    两种玄学优化:1、入列计数 tot >= n * 2 跳出;2、使用 stack 代替 queue

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const ll _inf(0x3f3f3f3f3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(2e3 + 10);
    const int maxm(3e3 + 10);
    bool vis[maxn];
    int ecnt, head[maxn], cnt[maxn], dis[maxn];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm << 1];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    bool spfa(int tot)
    {
        queue<int> q;
        vis[1] = true;
        dis[1] = 0;
        q.push(1);
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for (int i = head[u]; ~i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if (not vis[v]) {
                        cnt[v] = cnt[u] + 1;
                        if (cnt[v] >= tot) {
                            return true;
                        }
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        return false;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int t = read();
        while (t--) {
            ecnt = 0;
            memset(head, -1, sizeof head);
            memset(dis, 0x3f, sizeof dis);
            memset(vis, false, sizeof vis);
            memset(cnt, 0, sizeof cnt);
            int n = read(), m = read();
            while (m--) {
                int u = read(), v = read(), w = read();
                addEdge(u, v, w);
                if (w >= 0) {
                    addEdge(v, u, w);
                }
            }
            printf("%s
    ", spfa(n) ? "YES" : "NO");
        }
        return 0;
    }
    

    洛谷 P5960 【模板】差分约束算法

    差分约束:求最小值→最长路,求最大值→最短路

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(5e3 + 10);
    const int maxm(1e4 + 10);
    bool vis[maxn];
    int ecnt, head[maxn], cnt[maxn], dis[maxn];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    bool spfa(int n)
    {
        memset(dis, 0x3f, sizeof dis);
        dis[0] = 0;
        queue<int> q;
        q.push(0);
        vis[0] = true;
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if (not vis[v]) {
                        vis[v] = true;
                        q.push(v);
                        cnt[v] = cnt[u] + 1;
                        if (cnt[v] >= n + 1) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        memset(head, -1, sizeof head);
        int n = read(), m = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(v, u, w);
        }
        for (int i = 0; i <= n; ++i) {
            addEdge(0, i, 0);
        }
        if (spfa(n)) {
            for (int i = 1; i <= n; ++i) {
                write(dis[i], " 
    "[i == n]);
            }
        } else {
            printf("NO
    ");
        }
        return 0;
    }
    

    Kruskal 算法

    洛谷 P3366 【模板】最小生成树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(5e3 + 10);
    const int maxm(2e5 + 10);
    int pre[maxn];
    
    struct edge {
        int u, v, w;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int Find(int cur)
    {
        return pre[cur] == cur ? cur : pre[cur] = Find(pre[cur]);
    }
    
    inline void Union(int u, int v)
    {
        pre[Find(v)] = Find(u);
    }
    
    int kruskal(int n, int m)
    {
        int sum = 0, cnt = 0;
        for (int i = 0; i < m and cnt < n - 1; ++i) {
            int u = edges[i].u, v = edges[i].v, w = edges[i].w;
            if (Find(u) not_eq Find(v)) {
                Union(u, v);
                ++cnt;
                sum += w;
            }
        }
        return cnt == n - 1 ? sum : -1;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            pre[i] = i;
        }
        for (int i = 0; i < m; ++i) {
            edges[i].u = read();
            edges[i].v = read();
            edges[i].w = read();
        }
        sort(edges, edges + m, [&](const edge& a, const edge& b) {
            return a.w < b.w;
        });
        int res = kruskal(n, m);
        if (compl res) {
            write(res, true);
        } else {
            puts("orz");
        }
        return 0;
    }
    

    Prim 算法

    洛谷 P3366 【模板】最小生成树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int inf(0x3f3f3f3f);
    const int maxn(5e3 + 10);
    const int maxm(4e5 + 10);
    int ecnt, head[maxn];
    int dis[maxn];
    bool vis[maxn];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    int prim(int n, int m)
    {
        memset(dis, 0x3f, sizeof dis);
        dis[1] = 0;
        priority_queue<p, vector<p>, greater<p>> q;
        for (int i = 1; i <= n; ++i) {
            q.push(p(dis[i], i));
        }
        int sum = 0;
        while (not q.empty()) {
            int u = q.top().second;
            q.pop();
            if (vis[u]) continue;
            vis[u] = true;
            if (dis[u] == inf) return -1;
            sum += dis[u];
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (dis[v] > w) {
                    dis[v] = w;
                    q.push(p(dis[v], v));
                }
            }
        }
        return sum;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        int n = read(), m = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
            addEdge(v, u, w);
        }
        int res = prim(n, m);
        if (compl res) {
            write(res, true);
        } else {
            puts("orz");
        }
        return 0;
    }
    

    倍增

    洛谷 P3379 【模板】最近公共祖先(LCA)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(5e5 + 10);
    const int maxm(1e6 + 10);
    int ecnt, head[maxn];
    int dep[maxn], f[maxn][20];
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void addEdge(int u, int v)
    {
        edges[ecnt].to = v;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void bfs(int root)
    {
        queue<int> q;
        q.push(root);
        dep[root] = 1;
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to;
                if (dep[v]) {
                    continue;
                }
                q.push(v);
                dep[v] = dep[u] + 1;
                f[v][0] = u;
                for (int j = 1; j < 20; ++j) {
                    f[v][j] = f[f[v][j - 1]][j - 1];
                }
            }
        }
    }
    
    int lca(int u, int v)
    {
        if (dep[u] < dep[v]) {
            swap(u, v);
        }
        for (int i = 19; i >= 0; --i) {
            if (dep[f[u][i]] >= dep[v]) {
                u = f[u][i];
            }
        }
        if (u == v) {
            return u;
        }
        for (int i = 19; i >= 0; --i) {
            if (f[u][i] not_eq f[v][i]) {
                u = f[u][i];
                v = f[v][i];
            }
        }
        return f[u][0];
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        memset(head, -1, sizeof head);
        int n = read(), m = read(), s = read();
        for (int i = 0; i < n - 1; ++i) {
            int u = read(), v = read();
            addEdge(u, v);
            addEdge(v, u);
        }
        bfs(s);
        while (m--) {
            int u = read(), v = read();
            write(lca(u, v), true);
        }
        return 0;
    }
    

    洛谷 P4180 [BJWC2010]严格次小生成树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int maxn(1e6 + 10);
    const int maxm(3e6 + 10);
    int ecnt, head[maxn];
    int pre[maxn], dep[maxn];
    int f[maxn][17], d1[maxn][17], d2[maxn][17];
    
    struct edge {
        int u, v, w;
        bool used;
        
        bool operator <(const edge& rhs) const
        {
            return w < rhs.w;
        }
    } edges[maxm];
    
    struct _edge {
        int to, wt, nxt;
    } _edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void addEdge(int u, int v, int w)
    {
        _edges[ecnt].to = v;
        _edges[ecnt].wt = w;
        _edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    int Find(int x)
    {
        return pre[x] == x ? x : pre[x] = Find(pre[x]);
    }
    
    void Union(int u, int v)
    {
        pre[Find(v)] = Find(u);
    }
    
    ll kruskal(int n, int m)
    {
        for (int i = 1; i <= n; ++i) {
            pre[i] = i;
        }
        sort(edges, edges + m);
        ll res = 0;
        for (int i = 0; i < m; ++i) {
            int u = edges[i].u, v = edges[i].v, w = edges[i].w;
            if (Find(u) != Find(v)) {
                Union(u, v);
                res += w;
                edges[i].used = true;
            }
        }
        return res;
    }
    
    void build(int m)
    {
        memset(head, -1, sizeof head);
        for (int i = 0; i < m; ++i) {
            if (edges[i].used) {
                int u = edges[i].u, v = edges[i].v, w = edges[i].w;
                addEdge(u, v, w);
                addEdge(v, u, w);
            }
        }
    }
    
    void bfs(int root)
    {
        dep[root] = 1;
        queue<int> q;
        q.push(root);
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; compl i; i = _edges[i].nxt) {
                int v = _edges[i].to, w = _edges[i].wt;
                if (dep[v]) {
                    continue;
                }
                dep[v] = dep[u] + 1;
                q.push(v);
                f[v][0] = u;
                d1[v][0] = w;
                d2[v][0] = -inf;
                for (int j = 1; j < 17; ++j) {
                    int anc = f[v][j - 1];
                    f[v][j] = f[anc][j - 1];
                    int dis[4] = { d1[v][j - 1], d2[v][j - 1], d1[anc][j - 1], d2[anc][j - 1] };
                    d1[v][j] = d2[v][j] = -inf;
                    for (int k = 0; k < 4; ++k) {
                        int d = dis[k];
                        if (d > d1[v][j]) {
                            d2[v][j] = d1[v][j];
                            d1[v][j] = d;
                        } else if (d not_eq d1[v][j] and d > d2[v][j]) {
                            d2[v][j] = d;
                        }
                    }
                }
            }
        }
    }
    
    int lca(int u, int v, int w)
    {
        static int dis[maxn * 2];
        int cnt = 0;
        if (dep[u] < dep[v]) {
            swap(u, v);
        }
        for (int i = 16; i >= 0; --i) {
            if (dep[f[u][i]] >= dep[v]) {
                dis[cnt++] = d1[u][i];
                dis[cnt++] = d2[u][i];
                u = f[u][i];
            }
        }
        if (u not_eq v) {
            for (int i = 16; i >= 0; --i) {
                if (f[u][i] not_eq f[v][i]) {
                    dis[cnt++] = d1[u][i];
                    dis[cnt++] = d2[u][i];
                    dis[cnt++] = d1[v][i];
                    dis[cnt++] = d2[v][i];
                    u = f[u][i];
                    v = f[v][i];
                }
            }
            dis[cnt++] = d1[u][0];
            dis[cnt++] = d1[v][0];
        }
        int dis1 = -inf, dis2 = -inf;
        for (int i = 0; i < cnt; ++i) {
            int d = dis[i];
            if (d > dis1) {
                dis2 = dis1;
                dis1 = d;
            } else if (d not_eq dis1 and d > dis2) {
                dis2 = d;
            }
        }
        if (w > dis1) {
            return w - dis1;
        }
        if (w > dis2) {
            return w - dis2;
        }
        return inf;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        int n = read(), m = read();
        for (int i = 0; i < m; ++i) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
            edges[i] = edge{ u, v, w };
        }
        ll sum = kruskal(n, m);
        build(m);
        bfs(1);
        ll res = 1e18;
        for (int i = 0; i < m; ++i) {
            if (not edges[i].used) {
                int u = edges[i].u, v = edges[i].v, w = edges[i].w;
                res = min(res, sum + lca(u, v, w));
            }
        }
        write(res, true);
        return 0;
    }
    

    离线 Tarjan 算法

    洛谷 P3379 【模板】最近公共祖先(LCA)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(5e5 + 10);
    const int maxm(1e6 + 10);
    int ecnt, qcnt;
    bool vis[maxn];
    int ehead[maxn], qhead[maxm];
    int pre[maxn], ans[maxm];
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    struct que {
        int id, to, nxt;
    } ques[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void addEdge(int u, int v)
    {
        edges[ecnt].to = v;
        edges[ecnt].nxt = ehead[u];
        ehead[u] = ecnt++;
    }
    
    void addQue(int id, int u, int v)
    {
        ques[qcnt].id = id;
        ques[qcnt].to = v;
        ques[qcnt].nxt = qhead[u];
        qhead[u] = qcnt++;
    }
    
    int Find(int x)
    {
        return pre[x] == x ? x : pre[x] = Find(pre[x]);
    }
    
    void Union(int u, int v)
    {
        pre[Find(v)] = Find(u);
    }
    
    void dfs(int cur, int pre)
    {
        vis[cur] = true;
        for (int i = ehead[cur]; compl i; i = edges[i].nxt) {
            int nxt = edges[i].to;
            if (nxt not_eq pre) {
                dfs(nxt, cur);
            }
        }
        for (int i = qhead[cur]; compl i; i = ques[i].nxt) {
            int id = ques[i].id, nxt = ques[i].to;
            if (vis[nxt]) {
                ans[id] = Find(nxt);
            }
        }
        Union(pre, cur);
    }
    
    void tarjan(int tot, int root)
    {
        for (int i = 1; i <= tot; ++i) {
            pre[i] = i;
        }
        dfs(root, 0);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        memset(ehead, -1, sizeof ehead);
        memset(qhead, -1, sizeof qhead);
        int n = read(), m = read(), s = read();
        for (int i = 0; i < n - 1; ++i) {
            int u = read(), v = read();
            addEdge(u, v);
            addEdge(v, u);
        }
        for (int i = 0; i < m; ++i) {
            int u = read(), v = read();
            addQue(i, u, v);
            addQue(i, v, u);
        }
        tarjan(n, s);
        for (int i = 0; i < m; ++i) {
            write(ans[i], true);
        }
        return 0;
    }
    

    Tarjan 算法

    洛谷 P3388 【模板】割点(割顶)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(2e4 + 10);
    const int maxm(2e5 + 10);
    int ecnt, head[maxn];
    int tim, dfn[maxn], low[maxn];
    int ccnt;
    bool cut[maxn];
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void addEdge(int u, int v)
    {
        edges[ecnt].to = v;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void tarjan(int cur, int pre)
    {
        int child = 0;
        dfn[cur] = low[cur] = ++tim;
        for (int i = head[cur]; compl i; i = edges[i].nxt) {
            int nxt = edges[i].to;
            if (not dfn[nxt]) {
                ++child;
                tarjan(nxt, cur);
                low[cur] = min(low[cur], low[nxt]);
                if (pre not_eq cur and low[nxt] >= dfn[cur] and not cut[cur]) {
                    ++ccnt;
                    cut[cur] = true;
                }
            } else if (nxt not_eq pre) {
                low[cur] = min(low[cur], dfn[nxt]);
            }
        }
        if (pre == cur and child >= 2) {
            ++ccnt;
            cut[cur] = true;
        }
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        memset(head, -1, sizeof head);
        int n = read(), m = read();
        while (m--) {
            int u = read(), v = read();
            addEdge(u, v);
            addEdge(v, u);
        }
        for (int i = 1; i <= n; ++i) {
            if (not dfn[i]) {
                tarjan(i, i);
            }
        }
        write(ccnt, true);
        for (int i = 1; i <= n; ++i) {
            if (cut[i]) {
                write(i, false);
                putchar(32);
            }
        }
        return 0;
    }
    

    洛谷 P3387 【模板】缩点

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(1e4 + 10);
    const int maxm(2e5 + 10);
    int ecnt, head[maxn], shead[maxn];
    int tim, dfn[maxn], low[maxn];
    int scnt, scc[maxn], siz[maxn];
    int w[maxn], sum[maxn], deg[maxn];
    bool vis[maxn];
    stack<int> st;
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void addEdge(int u, int v, bool s = false)
    {
        edges[ecnt].to = v;
        if (s) {
            edges[ecnt].nxt = shead[u];
            shead[u] = ecnt++;
        } else {
            edges[ecnt].nxt = head[u];
            head[u] = ecnt++;
        }
    }
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++tim;
        st.push(u);
        vis[u] = true;
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to;
            if (not dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (vis[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u]) {
            ++scnt;
            int v = 0;
            do {
                v = st.top();
                st.pop();
                vis[v] = false;
                scc[v] = scnt;
                ++siz[scnt];
                sum[scnt] += w[v];
            } while (v not_eq u);
        }
    }
    
    int dfs(int u)
    {
        int mx = 0;
        for (int i = shead[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to;
            mx = max(mx, dfs(v));
        }
        return sum[u] + mx;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        memset(shead, -1, sizeof shead);
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            w[i] = read();
        }
        while (m--) {
            int u = read(), v = read();
            addEdge(u, v);
        }
        for (int i = 1; i <= n; ++i) {
            if (not dfn[i]) {
                tarjan(i);
            }
        }
        for (int u = 1; u <= n; ++u) {
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to;
                int a = scc[u], b = scc[v];
                if (a not_eq b) {
                    addEdge(a, b, true);
                    ++deg[b];
                }
            }
        }
        int res = 0;
        for (int i = 1; i <= scnt; ++i) {
            if (not deg[i]) {
                res = max(res, dfs(i));
            }
        }
        write(res, true);
        return 0;
    }
    

    洛谷 P4782 【模板】2-SAT 问题

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(2e6 + 10);
    const int maxm(2e6 + 10);
    int ecnt, head[maxn];
    int tim, dfn[maxn], low[maxn];
    int scnt, id[maxn];
    bool vis[maxn];
    stack<int> st;
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c = false)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    void addEdge(int u, int v)
    {
        edges[ecnt].to = v;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++tim;
        st.push(u);
        vis[u] = true;
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to;
            if (not dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (vis[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u]) {
            int v = -1;
            ++scnt;
            do {
                v = st.top();
                st.pop();
                vis[v] = false;
                id[v] = scnt;
            } while (u not_eq v);
        }
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        memset(head, -1, sizeof head);
        while (m--) {
            int u = read() - 1, a = read(), v = read() - 1, b = read();
            addEdge(u * 2 + not a, v * 2 + b);
            addEdge(v * 2 + not b, u * 2 + a);
        }
        for (int i = 0; i < n * 2; ++i) {
            if (not dfn[i]) {
                tarjan(i);
            }
        }
        bool flag = false;
        for (int i = 0; i < n; ++i) {
            if (id[i * 2] == id[i * 2 + 1]) {
                flag = true;
                break;
            }
        }
        if (flag) {
            puts("IMPOSSIBLE");
        } else {
            puts("POSSIBLE");
            for (int i = 0; i < n; ++i) {
                if (id[i * 2] < id[i * 2 + 1]) {
                    write(0, ' ');
                } else {
                    write(1, ' ');
                }
            }
        }
        return 0;
    }
    

    Hungary 算法

    洛谷 P3386 【模板】二分图最大匹配

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(1e3 + 10);
    const int maxm(1e5 + 10);
    int ecnt, head[maxn];
    bool vis[maxn];
    int match[maxn];
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void addEdge(int u, int v)
    {
        edges[ecnt].to = v;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    bool dfs(int u)
    {
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to;
            if (not vis[v]) {
                vis[v] = true;
                if (not match[v] or dfs(match[v])) {
                    match[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int hungary(int n)
    {
        int res = 0;
        for (int i = 1; i <= n; ++i) {
            memset(vis, false, sizeof vis);
            res += dfs(i);
        }
        return res;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        memset(head, -1, sizeof head);
        int n = read(), m = read(), e = read();
        while (e--) {
            int u = read(), v = read() + n;
            addEdge(u, v);
            addEdge(v, u);
        }
        write(hungary(n), true);
        return 0;
    }
    

    A* 算法

    POJ 2449 Remmarguts' Date

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e3 + 10);
    const int maxm(2e5 + 10);
    int ecnt, head[maxn], rhead[maxn];
    bool vis[maxn];
    int g[maxn];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline void addEdge(int u, int v, int w, bool r)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        if (r) {
            edges[ecnt].nxt = rhead[u];
            rhead[u] = ecnt++;
        } else {
            edges[ecnt].nxt = head[u];
            head[u] = ecnt++;
        }
    }
    
    void dijkstra(int src)
    {
        memset(g, 0x3f, sizeof g);
        g[src] = 0;
        priority_queue<p, vector<p>, greater<p>> q;
        q.push(p(0, src));
        while (not q.empty()) {
            int u = q.top().second;
            q.pop();
            if (vis[u]) continue;
            vis[u] = true;
            for (int i = rhead[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                if (g[v] > g[u] + w) {
                    g[v] = g[u] + w;
                    q.push(p(g[v], v));
                }
            }
        }
    }
    
    int astar(int src, int des, int k)
    {
        if (src == des) ++k;
        auto cmp = [&](const p& a, const p& b) {
            return a.second + g[a.first] > b.second + g[b.first];
        };
        priority_queue<p, vector<p>, decltype(cmp)> q(cmp);
        q.push(p(src, 0));
        int cnt = 0;
        while (not q.empty()) {
            int u = q.top().first, d = q.top().second;
            q.pop();
            if (u == des and ++cnt == k) {
                return d;
            }
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].wt;
                q.push(p(v, d + w));
            }
        }
        return -1;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        memset(rhead, -1, sizeof rhead);
        int n = read(), m = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w, false);
            addEdge(v, u, w, true);
        }
        int s = read(), t = read(), k = read();
        dijkstra(t);
        write(astar(s, t, k), true);
        return 0;
    }
    

    EK 算法

    洛谷 P3376 【模板】网络最大流

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int inf(0x3f3f3f3f);
    const int maxn(1e3 + 10);
    const int maxm(2e4 + 10);
    int ecnt, head[maxn];
    int mn[maxn], pre[maxn];
    bool vis[maxn];
    
    struct edge {
        int to, flow, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].flow = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    bool bfs(int src, int des)
    {
        queue<int> q;
        memset(vis, false, sizeof vis);
        q.push(src);
        vis[src] = true;
        mn[src] = inf;
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].flow;
                if (not vis[v] and w) {
                    vis[v] = true;
                    mn[v] = min(mn[u], w);
                    pre[v] = i;
                    if (v == des) {
                        return true;
                    }
                    q.push(v);
                }
            }
        }
        return false;
    }
    
    ll ek(int src, int des)
    {
        ll res = 0;
        while (bfs(src, des)) {
            res += mn[des];
            for (int i = des; i not_eq src; i = edges[pre[i] xor 1].to) {
                edges[pre[i]].flow -= mn[des];
                edges[pre[i] xor 1].flow += des;
            }
        }
        return res;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        int n = read(), m = read(), s = read(), t = read();
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
            addEdge(v, u, 0);
        }
        write(ek(s, t), true);
        return 0;
    }
    

    Dinic 算法

    洛谷 P3376 【模板】网络最大流

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int inf(0x3f3f3f3f);
    const int maxn(1e4 + 10);
    const int maxm(2e5 + 10);
    int ecnt, head[maxn];
    int dep[maxn], cur[maxn];
    
    struct edge {
        int to, flow, nxt;
    } edges[maxm];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].flow = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    bool bfs(int src, int des)
    {
        queue<int> q;
        memset(dep, -1, sizeof(dep));
        dep[src] = 0;
        q.push(src);
        while (not q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; compl i; i = edges[i].nxt) {
                int v = edges[i].to, w = edges[i].flow;
                if (dep[v] == -1 and w) {
                    q.push(v);
                    dep[v] = dep[u] + 1;
                }
            }
        }
        return compl dep[des];
    }
    
    int dfs(int u, int des, int rflow)
    {
        if (u == des) return rflow;
        int res = 0;
        for (int i = cur[u]; compl i and rflow; i = edges[i].nxt) {
            int v = edges[i].to;
            if (dep[v] not_eq dep[u] + 1 or not edges[i].flow) continue;
            cur[u] = i;
            int flow = dfs(v, des, min(edges[i].flow, rflow));
            edges[i].flow -= flow;
            edges[i xor 1].flow += flow;
            rflow -= flow;
            res += flow;
        }
        if (not res) dep[u] = -1;
        return res;
    }
    
    ll dinic(int src, int des)
    {
        ll res = 0;
        while (bfs(src, des)) {
            memcpy(cur, head, sizeof(head));
            res += dfs(src, des, inf);
        }
        return res;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read(), s = read(), t = read();
        memset(head, -1, sizeof(head));
        while (m--) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
            addEdge(v, u, 0);
        }
        write(dinic(s, t), true);
        return 0;
    }
    

    数据结构

    线段树

    洛谷 P3372 【模板】线段树 1

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    
    struct node {
        int l, r;
        ll sum, lz;
    } tree[maxn << 2];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int ls(int cur)
    {
        return cur << 1;
    }
    
    inline int rs(int cur)
    {
        return cur << 1 | 1;
    }
    
    void push_up(int cur)
    {
        tree[cur].sum = tree[ls(cur)].sum + tree[rs(cur)].sum;
    }
    
    void push_down(int cur)
    {
        if (tree[cur].lz) {
            tree[ls(cur)].sum += (tree[ls(cur)].r - tree[ls(cur)].l + 1) * tree[cur].lz;
            tree[rs(cur)].sum += (tree[rs(cur)].r - tree[rs(cur)].l + 1) * tree[cur].lz;
            tree[ls(cur)].lz += tree[cur].lz;
            tree[rs(cur)].lz += tree[cur].lz;
            tree[cur].lz = 0;
        }
    }
    
    void build(int cur, int l, int r)
    {
        tree[cur].l = l;
        tree[cur].r = r;
        tree[cur].lz = 0;
        if (l == r) {
            tree[cur].sum = read();
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(cur), l, mid);
        build(rs(cur), mid + 1, r);
        push_up(cur);
    }
    
    void update(int cur, int l, int r, int v)
    {
        if (tree[cur].l == l and tree[cur].r == r) {
            tree[cur].sum += (r - l + 1) * v;
            tree[cur].lz += v;
            return;
        }
        push_down(cur);
        int mid = (tree[cur].l + tree[cur].r) >> 1;
        if (r <= mid) {
            update(ls(cur), l, r, v);
        } else if (l > mid) {
            update(rs(cur), l, r, v);
        } else {
            update(ls(cur), l, mid, v);
            update(rs(cur), mid + 1, r, v);
        }
        push_up(cur);
    }
    
    ll query(int cur, int l, int r)
    {
        if (tree[cur].l == l and tree[cur].r == r) {
            return tree[cur].sum;
        }
        push_down(cur);
        int mid = (tree[cur].l + tree[cur].r) >> 1;
        if (r <= mid) return query(ls(cur), l, r);
        if (l > mid) return query(rs(cur), l, r);
        return query(ls(cur), l, mid) + query(rs(cur), mid + 1, r);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        build(1, 1, n);
        while (m--) {
            int t = read(), x = read(), y = read();
            if (t == 1) {
                int k = read();
                update(1, x, y, k);
            } else {
                write(query(1, x, y), true);
            }
        }
        return 0;
    }
    

    洛谷 P3373 【模板】线段树 2

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    int mod;
    
    struct {
        int l, r;
        ll val, add, mult;
    } tree[maxn << 2];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int ls(int cur)
    {
        return cur << 1;
    }
    
    inline int rs(int cur)
    {
        return cur << 1 | 1;
    }
    
    void push_up(int cur)
    {
        tree[cur].val = (tree[ls(cur)].val + tree[rs(cur)].val) % mod;
    }
    
    void push_down(int cur)
    {
        if (tree[cur].add or tree[cur].mult not_eq 1) {
            tree[ls(cur)].val = ((tree[ls(cur)]).val * tree[cur].mult + (tree[ls(cur)].r - tree[ls(cur)].l + 1) * tree[cur].add) % mod;
            tree[rs(cur)].val = ((tree[rs(cur)]).val * tree[cur].mult + (tree[rs(cur)].r - tree[rs(cur)].l + 1) * tree[cur].add) % mod;
            tree[ls(cur)].mult = tree[ls(cur)].mult * tree[cur].mult % mod;
            tree[rs(cur)].mult = tree[rs(cur)].mult * tree[cur].mult % mod;
            tree[ls(cur)].add = (tree[ls(cur)].add * tree[cur].mult + tree[cur].add) % mod;
            tree[rs(cur)].add = (tree[rs(cur)].add * tree[cur].mult + tree[cur].add) % mod;
            tree[cur].add = 0;
            tree[cur].mult = 1;
        }
    }
    
    void build(int cur, int l, int r)
    {
        tree[cur].l = l;
        tree[cur].r = r;
        tree[cur].mult = 1;
        if (l == r) {
            tree[cur].val = read();
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(cur), l, mid);
        build(rs(cur), mid + 1, r);
        push_up(cur);
    }
    
    void update(int cur, int l, int r, int op, int v)
    {
        if (tree[cur].l == l and tree[cur].r == r) {
            if (op == 1) {
                tree[cur].val = tree[cur].val * v % mod;
                tree[cur].add = tree[cur].add * v % mod;
                tree[cur].mult = tree[cur].mult * v % mod;
            } else {
                tree[cur].val = (tree[cur].val + (r - l + 1) * v) % mod;
                tree[cur].add = (tree[cur].add + v) % mod;
            }
            return;
        }
        push_down(cur);
        int mid = (tree[cur].l + tree[cur].r) >> 1;
        if (r <= mid) {
            update(ls(cur), l, r, op, v);
        } else if (l > mid) {
            update(rs(cur), l, r, op, v);
        } else {
            update(ls(cur), l, mid, op, v);
            update(rs(cur), mid + 1, r, op, v);
        }
        push_up(cur);
    }
    
    ll query(int cur, int l, int r)
    {
        if (tree[cur].l == l and tree[cur].r == r) {
            return tree[cur].val;
        }
        push_down(cur);
        int mid = (tree[cur].l + tree[cur].r) >> 1;
        if (r <= mid) {
            return query(ls(cur), l, r);
        }
        if (l > mid) {
            return query(rs(cur), l, r);
        }
        return (query(ls(cur), l, mid) + query(rs(cur), mid + 1, r)) % mod;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        mod = read();
        build(1, 1, n);
        while (m--) {
            int op = read(), x = read(), y = read();
            if (op == 3) {
                write(query(1, x, y), true);
            } else {
                update(1, x, y, op, read());
            }
        }
        return 0;
    }
    

    树状数组

    洛谷 P3374 【模板】树状数组 1

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(5e5 + 10);
    int c[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int lowbit(int x)
    {
        return x & -x;
    }
    
    void update(int p, int n, int v)
    {
        for (int i = p; i <= n; i += lowbit(i)) {
            c[i] += v;
        }
    }
    
    ll getSum(int p)
    {
        ll sum = 0;
        while (p) {
            sum += c[p];
            p -= lowbit(p);
        }
        return sum;
    }
    
    ll query(int l, int r)
    {
        return getSum(r) - getSum(l - 1);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            update(i, n, read());
        }
        while (m--) {
            int op = read(), a = read(), b = read();
            if (op == 1) {
                update(a, n, b);
            } else {
                write(query(a, b), true);
            }
        }
        return 0;
    }
    

    洛谷 P3368 【模板】树状数组 2

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(5e5 + 10);
    int c[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int lowbit(int x)
    {
        return x & -x;
    }
    
    void update(int p, int n, int v)
    {
        for (int i = p; i <= n; i += lowbit(i)) {
            c[i] += v;
        }
    }
    
    ll getSum(int p)
    {
        ll sum = 0;
        while (p) {
            sum += c[p];
            p -= lowbit(p);
        }
        return sum;
    }
    
    ll query(int l, int r)
    {
        return getSum(r) - getSum(l - 1);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            update(i, n, read());
        }
        while (m--) {
            int op = read(), a = read(), b = read();
            if (op == 1) {
                update(a, n, b);
            } else {
                write(query(a, b), true);
            }
        }
        return 0;
    }
    

    洛谷 P3372 【模板】线段树 1

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    int a[maxn];
    ll c[maxn][2];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int lowbit(int x)
    {
        return x & -x;
    }
    
    void add(int t, int p, int n, ll v)
    {
        for (int i = p; i <= n; i += lowbit(i)) {
            c[i][t] += v;
        }
    }
    
    ll getSum(int t, int p)
    {
        ll sum = 0;
        for (int i = p; i; i -= lowbit(i)) {
            sum += c[i][t];
        }
        return sum;
    }
    
    void update(int l, int r, int n, int v)
    {
        add(0, l, n, v);
        add(0, r + 1, n, -v);
        add(1, l, n, 1ll * v * (l - 1));
        add(1, r + 1, n, -1ll * v * r);
    }
    
    ll query(int l, int r)
    {
        ll sum_r = 1ll * r * getSum(0, r) - getSum(1, r);
        ll sum_l = 1ll * (l - 1) * getSum(0, l - 1) - getSum(1, l - 1);
        return sum_r - sum_l;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            a[i] = read();
            add(0, i, n, a[i] - a[i - 1]);
            add(1, i, n, 1ll * (a[i] - a[i - 1]) * (i - 1));
        }
        while (m--) {
            int op = read(), x = read(), y = read();
            if (op == 1) {
                int k = read();
                update(x, y, n, k);
            } else {
                write(query(x, y), true);
            }
        }
        return 0;
    }
    

    可持久化数组

    洛谷 P3919 【模板】可持久化线段树 1(可持久化数组)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(1e6 + 10);
    int cnt, a[maxn], root[maxn];
    
    struct node {
        int val, l, r;
    } tree[maxn * 40];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    void build(int l, int r, int& cur)
    {
        cur = ++cnt;
        if (l == r) {
            tree[cur].val = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, tree[cur].l);
        build(mid + 1, r, tree[cur].r);
    }
    
    void update(int l, int r, int pos, int val, int pre, int& cur)
    {
        tree[cur = ++cnt] = tree[pre];
        if (l == r) {
            tree[cur].val = val;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            update(l, mid, pos, val, tree[pre].l, tree[cur].l);
        } else {
            update(mid + 1, r, pos, val, tree[pre].r, tree[cur].r);
        }
    }
    
    int query(int l, int r, int pos, int cur)
    {
        if (l == r) {
            return tree[cur].val;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            return query(l, mid, pos, tree[cur].l);
        }
        return query(mid + 1, r, pos, tree[cur].r);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            a[i] = read();
        }
        build(1, n, root[0]);
        for (int i = 1; i <= m; ++i) {
            int v = read(), op = read(), pos = read();
            if (op == 1) {
                int val = read();
                update(1, n, pos, val, root[v], root[i]);
            } else {
                write(query(1, n, pos, root[i] = root[v]), true);
            }
        }
        return 0;
    }
    
    #include <bits/stdc++.h>
    #include <ext/rope>
    
    using namespace std;
    using namespace __gnu_cxx;
    const int maxn(1e6 + 10);
    rope<int> rp[maxn];
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        int n, m;
        cin >> n >> m;
        rp[0].append(0);
        for (int i = 1; i <= n; ++i) {
            int x;
            cin >> x;
            rp[0].append(x);
        }
        for (int i = 1; i <= m; ++i) {
            int v, op, pos, val;
            cin >> v >> op >> pos;
            rp[i] = rp[v];
            if (op == 1) {
                cin >> val;
                rp[i].replace(pos, val);
            } else {
                cout << rp[i][pos] << endl;
            }
        }
        return 0;
    }
    

    主席树

    洛谷 P3834 【模板】可持久化线段树 2(主席树)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int mod(1e9 + 7);
    const int maxn(2e5 + 10);
    int cnt, a[maxn], root[maxn];
    vector<int> nums;
    
    struct node {
        int l, r, sum;
    } tree[maxn * 40];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int getId(int val)
    {
        return int(lower_bound(nums.begin(), nums.end(), val) - nums.begin()) + 1;
    }
    
    void insert(int l, int r, int pos, int pre, int& cur)
    {
        cur = ++cnt;
        tree[cur] = tree[pre];
        ++tree[cur].sum;
        if (l == r) return;
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            insert(l, mid, pos, tree[pre].l, tree[cur].l);
        } else {
            insert(mid + 1, r, pos, tree[pre].r, tree[cur].r);
        }
    }
    
    int query(int l, int r, int k, int pre, int cur)
    {
        if (l == r) return l;
        int mid = (l + r) >> 1;
        int dif = tree[tree[cur].l].sum - tree[tree[pre].l].sum;
        if (k <= dif) {
            return query(l, mid, k, tree[pre].l, tree[cur].l);
        }
        return query(mid + 1, r, k - dif, tree[pre].r, tree[cur].r);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            nums.push_back(a[i] = read());
        }
        sort(nums.begin(), nums.end());
        nums.erase(unique(nums.begin(), nums.end()), nums.end());
        for (int i = 1; i <= n; ++i) {
            int pos = getId(a[i]);
            insert(1, (int)nums.size(), pos, root[i - 1], root[i]);
        }
        while (m--) {
            int l = read(), r = read(), k = read();
            write(nums[query(1, (int)nums.size(), k, root[l - 1], root[r]) - 1], true);
        }
        return 0;
    }
    

    树堆(Treap)

    洛谷 P3369 【模板】普通平衡树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    const int inf(0x3f3f3f3f);
    int idx, root;
    
    struct node {
        int l, r;
        int key, val;
        int cnt, siz;
    } tree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int new_node(int key)
    {
        ++idx;
        tree[idx].key = key;
        tree[idx].val = rand();
        tree[idx].cnt = tree[idx].siz = 1;
        return idx;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].siz = tree[tree[cur].l].siz + tree[tree[cur].r].siz + tree[cur].cnt;
    }
    
    inline void zig(int& cur)
    {
        int ls = tree[cur].l;
        tree[cur].l = tree[ls].r;
        tree[ls].r = cur;
        cur = ls;
        push_up(tree[cur].r);
        push_up(cur);
    }
    
    inline void zag(int& cur)
    {
        int rs = tree[cur].r;
        tree[cur].r = tree[rs].l;
        tree[rs].l = cur;
        cur = rs;
        push_up(tree[cur].l);
        push_up(cur);
    }
    
    void build()
    {
        root = new_node(-inf);
        tree[root].r = new_node(inf);
        push_up(root);
        if (tree[root].val < tree[tree[root].r].val) {
            zag(root);
        }
    }
    
    inline void insert(int& cur, int key)
    {
        if (not cur) {
            cur = new_node(key);
        } else if (key == tree[cur].key) {
            ++tree[cur].cnt;
        } else if (key < tree[cur].key) {
            insert(tree[cur].l, key);
            if (tree[tree[cur].l].val > tree[cur].val) {
                zig(cur);
            }
        } else {
            insert(tree[cur].r, key);
            if (tree[tree[cur].r].val > tree[cur].val) {
                zag(cur);
            }
        }
        push_up(cur);
    }
    
    inline void remove(int& cur, int key)
    {
        if (not cur) return;
        if (key == tree[cur].key) {
            if (tree[cur].cnt > 1) {
                --tree[cur].cnt;
            } else if (tree[cur].l or tree[cur].r) {
                if (not tree[cur].r or tree[tree[cur].l].val > tree[tree[cur].r].val) {
                    zig(cur);
                    remove(tree[cur].r, key);
                } else {
                    zag(cur);
                    remove(tree[cur].l, key);
                }
            } else {
                cur = 0;
            }
        } else if (key < tree[cur].key) {
            remove(tree[cur].l, key);
        } else {
            remove(tree[cur].r, key);
        }
        push_up(cur);
    }
    
    inline int get_rank(int cur, int key)
    {
        if (not cur) {
            return 0;
        }
        if (key == tree[cur].key) {
            return tree[tree[cur].l].siz + 1;
        }
        if (key < tree[cur].key) {
            return get_rank(tree[cur].l, key);
        }
        return get_rank(tree[cur].r, key) + tree[tree[cur].l].siz + tree[cur].cnt;
    }
    
    inline int get_key(int cur, int rank)
    {
        if (not cur) {
            return inf;
        }
        if (rank <= tree[tree[cur].l].siz) {
            return get_key(tree[cur].l, rank);
        }
        if (rank <= tree[tree[cur].l].siz + tree[cur].cnt) {
            return tree[cur].key;
        }
        return get_key(tree[cur].r, rank - tree[cur].cnt - tree[tree[cur].l].siz);
    }
    
    inline int get_prev(int cur, int key)
    {
        if (not cur) {
            return -inf;
        }
        if (key <= tree[cur].key) {
            return get_prev(tree[cur].l, key);
        }
        return max(tree[cur].key, get_prev(tree[cur].r, key));
    }
    
    inline int get_next(int cur, int key)
    {
        if (not cur) {
            return inf;
        }
        if (key >= tree[cur].key) {
            return get_next(tree[cur].r, key);
        }
        return min(tree[cur].key, get_next(tree[cur].l, key));
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        build();
        int n = read();
        while (n--) {
            int op = read(), x = read();
            if (op == 1) {
                insert(root, x);
            } else if (op == 2) {
                remove(root, x);
            } else if (op == 3) {
                write(get_rank(root, x) - 1, true);
            } else if (op == 4) {
                write(get_key(root, x + 1), true);
            } else if (op == 5) {
                write(get_prev(root, x), true);
            } else {
                write(get_next(root, x), true);
            }
        }
        return 0;
    }
    

    无旋树堆(fhq Treap)

    洛谷 P3369 【模板】普通平衡树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int inf(0x3f3f3f3f);
    const int maxn(1e5 + 10);
    int idx, root;
    int x, y, z;
    
    struct node {
        int l, r;
        int key, val;
        int siz;
    } tree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int new_node(int key)
    {
        ++idx;
        tree[idx].key = key;
        tree[idx].val = rand();
        tree[idx].siz = 1;
        return idx;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].siz = tree[tree[cur].l].siz + tree[tree[cur].r].siz + 1;
    }
    
    inline void split(int cur, int key, int& x, int& y)
    {
        if (not cur) {
            x = y = 0;
        } else if (tree[cur].key <= key) {
            x = cur;
            split(tree[cur].r, key, tree[cur].r, y);
            push_up(cur);
        } else {
            y = cur;
            split(tree[cur].l, key, x, tree[cur].l);
            push_up(cur);
        }
    }
    
    inline int merge(int x, int y)
    {
        if (not x or not y) {
            return x + y;
        }
        if (tree[x].val > tree[y].val) {
            tree[x].r = merge(tree[x].r, y);
            push_up(x);
            return x;
        }
        tree[y].l = merge(x, tree[y].l);
        push_up(y);
        return y;
    }
    
    inline void insert(int key)
    {
        split(root, key, x, y);
        root = merge(merge(x, new_node(key)), y);
    }
    
    inline void remove(int key)
    {
        split(root, key, x, z);
        split(x, key - 1, x, y);
        y = merge(tree[y].l, tree[y].r);
        root = merge(merge(x, y), z);
    }
    
    inline int get_rank(int key)
    {
        split(root, key - 1, x, y);
        int res = tree[x].siz + 1;
        root = merge(x, y);
        return res;
    }
    
    inline int get_key(int cur, int rank)
    {
        if (rank == tree[tree[cur].l].siz + 1) {
            return tree[cur].key;
        }
        if (rank <= tree[tree[cur].l].siz) {
            return get_key(tree[cur].l, rank);
        }
        return get_key(tree[cur].r, rank - tree[tree[cur].l].siz - 1);
    }
    
    inline int get_prev(int key)
    {
        split(root, key - 1, x, y);
        int cur = x;
        while (tree[cur].r) {
            cur = tree[cur].r;
        }
        int res = tree[cur].key;
        root = merge(x, y);
        return res;
    }
    
    inline int get_next(int key)
    {
        split(root, key, x, y);
        int cur = y;
        while (tree[cur].l) {
            cur = tree[cur].l;
        }
        int res = tree[cur].key;
        root = merge(x, y);
        return res;
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read();
        while (n--) {
            int op = read(), x = read();
            if (op == 1) {
                insert(x);
            } else if (op == 2) {
                remove(x);
            } else if (op == 3) {
                write(get_rank(x), true);
            } else if (op == 4) {
                write(get_key(root, x), true);
            } else if (op == 5) {
                write(get_prev(x), true);
            } else {
                write(get_next(x), true);
            }
        }
        return 0;
    }
    

    洛谷 P3391 【模板】文艺平衡树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const double pi(acos(-1));
    const int inf(0x3f3f3f3f);
    const int maxn(1e5 + 10);
    int idx, root;
    
    struct node {
        int l, r;
        int key, val;
        int siz;
        bool rev;
    } tree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    inline int new_node(int key)
    {
        ++idx;
        tree[idx].key = key;
        tree[idx].val = rand();
        tree[idx].siz = 1;
        return idx;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].siz = tree[tree[cur].l].siz + tree[tree[cur].r].siz + 1;
    }
    
    inline void push_down(int cur)
    {
        if (tree[cur].rev) {
            swap(tree[cur].l, tree[cur].r);
            tree[tree[cur].l].rev ^= 1;
            tree[tree[cur].r].rev ^= 1;
            tree[cur].rev = false;
        }
    }
    
    inline void split(int cur, int siz, int& x, int& y)
    {
        if (not cur) {
            x = y = 0;
        } else {
            push_down(cur);
            if (siz > tree[tree[cur].l].siz) {
                x = cur;
                split(tree[cur].r, siz - tree[tree[cur].l].siz - 1, tree[cur].r, y);
            } else {
                y = cur;
                split(tree[cur].l, siz, x, tree[cur].l);
            }
            push_up(cur);
        }
    }
    
    inline int merge(int x, int y)
    {
        if (not x or not y) {
            return x + y;
        }
        if (tree[x].val < tree[y].val) {
            push_down(x);
            tree[x].r = merge(tree[x].r, y);
            push_up(x);
            return x;
        }
        push_down(y);
        tree[y].l = merge(x, tree[y].l);
        push_up(y);
        return y;
    }
    
    inline void reverse(int l, int r)
    {
        int x, y, z;
        split(root, l - 1, x, y);
        split(y, r - l + 1, y, z);
        tree[y].rev ^= 1;
        root = merge(merge(x, y), z);
    }
    
    void dfs(int cur)
    {
        if (not cur) return;
        push_down(cur);
        dfs(tree[cur].l);
        write(tree[cur].key, ' ');
        dfs(tree[cur].r);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            root = merge(root, new_node(i));
        }
        while (m--) {
            int l = read(), r = read();
            reverse(l, r);
        }
        dfs(root);
        return 0;
    }
    

    伸展树(Splay)

    洛谷 P3369 【模板】普通平衡树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    int idx, root;
    
    struct node {
        int val;
        int siz, cnt;
        int fa, ch[2];
    } tree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int new_node(int val)
    {
        ++idx;
        tree[idx].val = val;
        tree[idx].siz = tree[idx].cnt = 1;
        return idx;
    }
    
    inline bool get_rel(int cur, int fa)
    {
        return tree[fa].ch[1] == cur;
    }
    
    inline void connect(int cur, int fa, int rel)
    {
        tree[fa].ch[rel] = cur;
        tree[cur].fa = fa;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].siz = tree[tree[cur].ch[0]].siz + tree[tree[cur].ch[1]].siz + tree[cur].cnt;
    }
    
    inline void rotate(int cur)
    {
        int fa = tree[cur].fa;
        int gf = tree[fa].fa;
        bool rel = get_rel(cur, fa);
        connect(tree[cur].ch[rel ^ 1], fa, rel);
        connect(cur, gf, get_rel(fa, gf));
        connect(fa, cur, rel ^ 1);
        push_up(fa);
        push_up(cur);
    }
    
    inline void splaying(int cur, int top)
    {
        while (tree[cur].fa not_eq top) {
            int fa = tree[cur].fa;
            int gf = tree[fa].fa;
            if (gf not_eq top) {
                get_rel(cur, fa) ^ get_rel(fa, gf) ? rotate(cur) : rotate(fa);
            }
            rotate(cur);
        }
        if (not top) {
            root = cur;
        }
    }
    
    inline void insert(int val)
    {
        int cur = root, fa = 0;
        while (cur and tree[cur].val not_eq val) {
            fa = cur;
            cur = tree[cur].ch[val > tree[cur].val];
        }
        if (cur) {
            ++tree[cur].cnt;
            ++tree[cur].siz;
        } else {
            cur = new_node(val);
            connect(cur, fa, val > tree[fa].val);
        }
        splaying(cur, 0);
    }
    
    inline void remove(int val)
    {
        int cur = root, fa = 0;
        while (tree[cur].val not_eq val) {
            fa = cur;
            cur = tree[cur].ch[val > tree[cur].val];
        }
        splaying(cur, 0);
        if (tree[cur].cnt > 1) {
            --tree[cur].cnt;
            --tree[cur].siz;
        } else if (tree[cur].ch[1]) {
            int nxt = tree[cur].ch[1];
            while (tree[nxt].ch[0]) {
                nxt = tree[nxt].ch[0];
            }
            splaying(nxt, cur);
            connect(tree[cur].ch[0], nxt, 0);
            root = nxt;
            tree[root].fa = 0;
            push_up(root);
        } else {
            root = tree[cur].ch[0];
            tree[root].fa = 0;
        }
    }
    
    inline int get_rank(int val)
    {
        int cur = root, rank = 1;
        while (cur) {
            if (tree[cur].val == val) {
                rank += tree[tree[cur].ch[0]].siz;
                splaying(cur, 0);
                break;
            } else if (val < tree[cur].val) {
                cur = tree[cur].ch[0];
            } else {
                rank += tree[tree[cur].ch[0]].siz + tree[cur].cnt;
                cur = tree[cur].ch[1];
            }
        }
        return rank;
    }
    
    inline int get_val(int rank)
    {
        int cur = root;
        while (cur) {
            int size_l = tree[tree[cur].ch[0]].siz;
            if (size_l + 1 <= rank and rank <= size_l + tree[cur].cnt) {
                splaying(cur, 0);
                break;
            } else if (size_l >= rank) {
                cur = tree[cur].ch[0];
            } else {
                rank -= size_l + tree[cur].cnt;
                cur = tree[cur].ch[1];
            }
        }
        return tree[cur].val;
    }
    
    inline int get_prev(int val)
    {
        return get_val(get_rank(val) - 1);
    }
    
    inline int get_next(int val)
    {
        return get_val(get_rank(val + 1));
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read();
        while (n--) {
            int op = read(), x = read();
            if (op == 1) {
                insert(x);
            } else if (op == 2) {
                remove(x);
            } else if (op == 3) {
                write(get_rank(x), true);
            } else if (op == 4) {
                write(get_val(x), true);
            } else if (op == 5) {
                write(get_prev(x), true);
            } else {
                write(get_next(x), true);
            }
        }
        return 0;
    }
    

    洛谷 P3391 【模板】文艺平衡树

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    int idx, root;
    
    struct node {
        int val, siz;
        int fa, ch[2];
        bool rev;
    } tree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, char c)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (c) putchar(c);
    }
    
    inline int new_node(int val)
    {
        ++idx;
        tree[idx].val = val;
        tree[idx].siz = 1;
        return idx;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].siz = tree[tree[cur].ch[0]].siz + tree[tree[cur].ch[1]].siz + 1;
    }
    
    inline void push_down(int cur)
    {
        if (tree[cur].rev) {
            swap(tree[cur].ch[0], tree[cur].ch[1]);
            tree[tree[cur].ch[0]].rev ^= 1;
            tree[tree[cur].ch[1]].rev ^= 1;
            tree[cur].rev = false;
        }
    }
    
    inline int get_rel(int cur, int fa)
    {
        return tree[fa].ch[1] == cur;
    }
    
    inline void connect(int cur, int fa, bool rel)
    {
        tree[fa].ch[rel] = cur;
        tree[cur].fa = fa;
    }
    
    inline void rotate(int cur)
    {
        int fa = tree[cur].fa;
        int gf = tree[fa].fa;
        bool rel = get_rel(cur, fa);
        connect(tree[cur].ch[rel ^ 1], fa, rel);
        connect(cur, gf, get_rel(fa, gf));
        connect(fa, cur, rel ^ 1);
        push_up(fa);
        push_up(cur);
    }
    
    inline void splaying(int cur, int top)
    {
        while (tree[cur].fa not_eq top) {
            int fa = tree[cur].fa;
            int gf = tree[fa].fa;
            if (gf not_eq top) {
                get_rel(cur, fa) ^ get_rel(fa, gf) ? rotate(cur) : rotate(fa);
            }
            rotate(cur);
        }
        if (not top) {
            root = cur;
        }
    }
    
    inline void insert(int val)
    {
        int cur = root, fa = 0;
        while (cur) {
            fa = cur;
            cur = tree[cur].ch[val > tree[cur].val];
        }
        cur = new_node(val);
        connect(cur, fa, val > tree[fa].val);
        splaying(cur, 0);
    }
    
    inline int get_id(int pos)
    {
        int cur = root;
        while (cur) {
            push_down(cur);
            if (tree[tree[cur].ch[0]].siz >= pos) {
                cur = tree[cur].ch[0];
            } else if (tree[tree[cur].ch[0]].siz + 1 == pos) {
                return cur;
            } else {
                pos -= tree[tree[cur].ch[0]].siz + 1;
                cur = tree[cur].ch[1];
            }
        }
        return cur;
    }
    
    inline void reverse(int l, int r)
    {
        int x = get_id(l - 1);
        int y = get_id(r + 1);
        splaying(x, 0);
        splaying(y, x);
        tree[tree[y].ch[0]].rev ^= 1;
    }
    
    void dfs(int cur, int n)
    {
        if (not cur) return;
        push_down(cur);
        dfs(tree[cur].ch[0], n);
        if (tree[cur].val >= 1 and tree[cur].val <= n) {
            write(tree[cur].val, ' ');
        }
        dfs(tree[cur].ch[1], n);
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        for (int i = 0; i <= n + 1; ++i) {
            insert(i);
        }
        while (m--) {
            int l = read() + 1, r = read() + 1;
            reverse(l, r);
        }
        dfs(root, n);
        return 0;
    }
    

    树套树

    洛谷 P3380 【模板】二逼平衡树(树套树)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int inf(INT_MAX);
    const int maxn(2e5 + 10);
    const int maxm(1e7 + 10);
    int idx, w[maxn];
    
    struct splayNode {
        int val;
        int cnt, siz;
        int fa, ch[2];
    } splay[maxm];
    
    struct segNode {
        int l, r, root;
    } segTree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int new_node(int val)
    {
        ++idx;
        splay[idx].val = val;
        splay[idx].cnt = splay[idx].siz = 1;
        return idx;
    }
    
    inline bool get_rel(int cur, int fa)
    {
        return splay[fa].ch[1] == cur;
    }
    
    inline void connect(int cur, int fa, bool rel)
    {
        splay[fa].ch[rel] = cur;
        splay[cur].fa = fa;
    }
    
    inline void push_up(int cur)
    {
        splay[cur].siz = splay[splay[cur].ch[0]].siz + splay[splay[cur].ch[1]].siz + splay[cur].cnt;
    }
    
    inline void rotate(int cur)
    {
        int fa = splay[cur].fa;
        int gf = splay[fa].fa;
        bool rel = get_rel(cur, fa);
        connect(splay[cur].ch[rel xor 1], fa, rel);
        connect(cur, gf, get_rel(fa, gf));
        connect(fa, cur, rel xor 1);
        push_up(fa);
        push_up(cur);
    }
    
    inline void splaying(int cur, int top, int& rt)
    {
        while (splay[cur].fa not_eq top) {
            int fa = splay[cur].fa;
            int gf = splay[fa].fa;
            if (gf not_eq top) {
                get_rel(cur, fa) xor get_rel(fa, gf) ? rotate(cur) : rotate(fa);
            }
            rotate(cur);
        }
        if (not top) rt = cur;
    }
    
    inline void insert(int val, int& rt)
    {
        int cur = rt, fa = 0;
        while (cur and splay[cur].val not_eq val) {
            fa = cur;
            cur = splay[cur].ch[val > splay[cur].val];
        }
        if (cur) {
            ++splay[cur].cnt;
            ++splay[cur].siz;
        } else {
            cur = new_node(val);
            connect(cur, fa, val > splay[fa].val);
        }
        splaying(cur, 0, rt);
    }
    
    inline void remove(int val, int& rt)
    {
        int cur = rt;
        while (cur and splay[cur].val not_eq val) {
            cur = splay[cur].ch[val > splay[cur].val];
        }
        splaying(cur, 0, rt);
        if (splay[cur].cnt > 1) {
            --splay[cur].cnt;
            --splay[cur].siz;
        } else if (splay[cur].ch[1]) {
            int nxt = splay[cur].ch[1];
            while (splay[nxt].ch[0]) {
                nxt = splay[nxt].ch[0];
            }
            splaying(nxt, cur, rt);
            connect(splay[cur].ch[0], nxt, false);
            rt = nxt;
            splay[rt].fa = splay[cur].ch[1] = 0;
            push_up(rt);
        } else {
            rt = splay[cur].ch[0];
            splay[rt].fa = splay[cur].ch[0] = 0;
            push_up(rt);
        }
    }
    
    inline int get_rank(int val, int& rt)
    {
        int cur = rt, rank = 0;
        while (cur) {
            if (val < splay[cur].val) {
                cur = splay[cur].ch[0];
            } else if (val > splay[cur].val) {
                rank += splay[splay[cur].ch[0]].siz + splay[cur].cnt;
                cur = splay[cur].ch[1];
            } else {
                rank += splay[splay[cur].ch[0]].siz;
                splaying(cur, 0, rt);
                break;
            }
        }
        return rank;
    }
    
    inline int get_val(int rank, int& rt)
    {
        int cur = rt;
        while (cur) {
            if (splay[splay[cur].ch[0]].siz >= rank) {
                cur = splay[cur].ch[0];
            } else if (splay[splay[cur].ch[0]].siz + splay[cur].cnt >= rank) {
                splaying(cur, 0, rt);
                break;
            } else {
                rank -= splay[splay[cur].ch[0]].siz + splay[cur].cnt;
                cur = splay[cur].ch[1];
            }
        }
        return splay[cur].val;
    }
    
    inline int get_prev(int val, int& rt)
    {
        return get_val(get_rank(val, rt), rt);
    }
    
    inline int get_next(int val, int& rt)
    {
        return get_val(get_rank(val + 1, rt) + 1, rt);
    }
    
    inline int ls(int cur)
    {
        return cur << 1;
    }
    
    inline int rs(int cur)
    {
        return cur << 1 bitor 1;
    }
    
    void build(int cur, int l, int r)
    {
        segTree[cur].l = l;
        segTree[cur].r = r;
        segTree[cur].root = new_node(-inf);
        insert(inf, segTree[cur].root);
        for (int i = l; i <= r; ++i) {
            insert(w[i], segTree[cur].root);
        }
        if (l == r) return;
        int mid = (l + r) >> 1;
        build(ls(cur), l, mid);
        build(rs(cur), mid + 1, r);
    }
    
    inline int query_rank(int cur, int l, int r, int v)
    {
        if (segTree[cur].l == l and segTree[cur].r == r) {
            return get_rank(v, segTree[cur].root) - 1;
        }
        int mid = (segTree[cur].l + segTree[cur].r) >> 1;
        if (r <= mid) {
            return query_rank(ls(cur), l, r, v);
        }
        if (l > mid) {
            return query_rank(rs(cur), l, r, v);
        }
        return query_rank(ls(cur), l, mid, v) + query_rank(rs(cur), mid + 1, r, v);
    }
    
    inline int query_val(int l, int r, int k)
    {
        int low = 0, high = 1e8;
        while (low < high) {
            int mid = (low + high + 1) >> 1;
            if (query_rank(1, l, r, mid) + 1 <= k) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }
        return high;
    }
    
    inline void update(int cur, int p, int v)
    {
        remove(w[p], segTree[cur].root);
        insert(v, segTree[cur].root);
        if (segTree[cur].l == segTree[cur].r) return;
        int mid = (segTree[cur].l + segTree[cur].r) >> 1;
        if (p <= mid) {
            update(ls(cur), p, v);
        } else {
            update(rs(cur), p, v);
        }
    }
    
    inline int query_prev(int cur, int l, int r, int v)
    {
        if (segTree[cur].l == l and segTree[cur].r == r) {
            return get_prev(v, segTree[cur].root);
        }
        int mid = (segTree[cur].l + segTree[cur].r) >> 1;
        if (r <= mid) {
            return query_prev(ls(cur), l, r, v);
        }
        if (l > mid) {
            return query_prev(rs(cur), l, r, v);
        }
        return max(query_prev(ls(cur), l, mid, v), query_prev(rs(cur), mid + 1, r, v));
    }
    
    inline int query_next(int cur, int l, int r, int v)
    {
        if (segTree[cur].l == l and segTree[cur].r == r) {
            return get_next(v, segTree[cur].root);
        }
        int mid = (segTree[cur].l + segTree[cur].r) >> 1;
        if (r <= mid) {
            return query_next(ls(cur), l, r, v);
        }
        if (l > mid) {
            return query_next(rs(cur), l, r, v);
        }
        return min(query_next(ls(cur), l, mid, v), query_next(rs(cur), mid + 1, r, v));
    }
    
    int main()
    {
    #ifdef ONLINE_JUDGE
    #else
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            w[i] = read();
        }
        build(1, 1, n);
        while (m--) {
            int op = read();
            if (op == 1) {
                int l = read(), r = read(), k = read();
                write(query_rank(1, l, r, k) + 1, true);
            } else if (op == 2) {
                int l = read(), r = read(), k = read();
                write(query_val(l, r, k), true);
            } else if (op == 3) {
                int p = read(), k = read();
                update(1, p, k);
                w[p] = k;
            } else if (op == 4) {
                int l = read(), r = read(), k = read();
                write(query_prev(1, l, r, k), true);
            } else {
                int l = read(), r = read(), k = read();
                write(query_next(1, l, r, k), true);
            }
        }
        return 0;
    }
    

    树链剖分

    洛谷 P3384 【模板】轻重链剖分

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    const int maxm(2e5 + 10);
    int mod, ecnt, v[maxn], head[maxn];
    int dep[maxn], siz[maxn], fa[maxn], son[maxn];
    int tim, dfn[maxn], top[maxn], w[maxn];
    
    struct edge {
        int to, nxt;
    } edges[maxm];
    
    struct node {
        int l, r;
        int sum, lz;
    } tree[maxn << 2];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline void addEdge(int u, int v)
    {
        edges[ecnt].to = v;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    inline int ls(int cur)
    {
        return cur << 1;
    }
    
    inline int rs(int cur)
    {
        return cur << 1 bitor 1;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].sum = tree[ls(cur)].sum + tree[rs(cur)].sum;
    }
    
    inline void push_down(int cur)
    {
        if (tree[cur].lz) {
            tree[ls(cur)].lz = (tree[ls(cur)].lz + tree[cur].lz) % mod;
            tree[rs(cur)].lz = (tree[rs(cur)].lz + tree[cur].lz) % mod;
            tree[ls(cur)].sum = (tree[ls(cur)].sum + (tree[ls(cur)].r - tree[ls(cur)].l + 1) * tree[cur].lz) % mod;
            tree[rs(cur)].sum = (tree[rs(cur)].sum + (tree[rs(cur)].r - tree[rs(cur)].l + 1) * tree[cur].lz) % mod;
            tree[cur].lz = false;
        }
    }
    
    void build(int cur, int l, int r)
    {
        tree[cur].l = l;
        tree[cur].r = r;
        if (l == r) {
            tree[cur].sum = w[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(cur), l, mid);
        build(rs(cur), mid + 1, r);
        push_up(cur);
    }
    
    void update(int cur, int l, int r, int v)
    {
        if (tree[cur].l == l and tree[cur].r == r) {
            tree[cur].sum = (tree[cur].sum + (r - l + 1) * v) % mod;
            tree[cur].lz = (tree[cur].lz + v) % mod;
            return;
        }
        push_down(cur);
        int mid = (tree[cur].l + tree[cur].r) >> 1;
        if (r <= mid) {
            update(ls(cur), l, r, v);
        } else if (l > mid) {
            update(rs(cur), l, r, v);
        } else {
            update(ls(cur), l, mid, v);
            update(rs(cur), mid + 1, r, v);
        }
        push_up(cur);
    }
    
    int query(int cur, int l, int r)
    {
        if (tree[cur].l == l and tree[cur].r == r) {
            return tree[cur].sum;
        }
        push_down(cur);
        int mid = (tree[cur].l + tree[cur].r) >> 1;
        if (r <= mid) {
            return query(ls(cur), l, r);
        }
        if (l > mid) {
            return query(rs(cur), l, r);
        }
        return (query(ls(cur), l, mid) + query(rs(cur), mid + 1, r)) % mod;
    }
    
    void dfs1(int cur, int pre)
    {
        fa[cur] = pre;
        dep[cur] = dep[pre] + 1;
        siz[cur] = 1;
        int maxsize = -1;
        for (int i = head[cur]; compl i; i = edges[i].nxt) {
            int nxt = edges[i].to;
            if (nxt == pre) continue;
            dfs1(nxt, cur);
            siz[cur] += siz[nxt];
            if (siz[nxt] > maxsize) {
                maxsize = siz[nxt];
                son[cur] = nxt;
            }
        }
    }
    
    void dfs2(int cur, int tp)
    {
        dfn[cur] = ++tim;
        w[tim] = v[cur];
        top[cur] = tp;
        if (not son[cur]) return;
        dfs2(son[cur], tp);
        for (int i = head[cur]; compl i; i = edges[i].nxt) {
            int nxt = edges[i].to;
            if (nxt not_eq fa[cur] and nxt not_eq son[cur]) {
                dfs2(nxt, nxt);
            }
        }
    }
    
    void update_chain(int u, int v, int val)
    {
        val %= mod;
        while (top[u] not_eq top[v]) {
            if (dep[top[u]] < dep[top[v]]) {
                swap(u, v);
            }
            update(1, dfn[top[u]], dfn[u], val);
            u = fa[top[u]];
        }
        if (dep[u] > dep[v]) {
            swap(u, v);
        }
        update(1, dfn[u], dfn[v], val);
    }
    
    int query_chain(int u, int v)
    {
        int res = 0;
        while (top[u] not_eq top[v]) {
            if (dep[top[u]] < dep[top[v]]) {
                swap(u, v);
            }
            res += query(1, dfn[top[u]], dfn[u]);
            u = fa[top[u]];
        }
        if (dep[u] > dep[v]) {
            swap(u, v);
        }
        res += query(1, dfn[u], dfn[v]);
        return res % mod;
    }
    
    inline void update_son(int cur, int val)
    {
        update(1, dfn[cur], dfn[cur] + siz[cur] - 1, val);
    }
    
    inline int query_son(int cur)
    {
        return query(1, dfn[cur], dfn[cur] + siz[cur] - 1);
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        int n = read(), m = read(), r = read();
        mod = read();
        for (int i = 1; i <= n; ++i) {
            v[i] = read();
        }
        for (int i = 1; i <= n - 1; ++i) {
            int u = read(), v = read();
            addEdge(u, v);
            addEdge(v, u);
        }
        dfs1(r, r);
        dfs2(r, r);
        build(1, 1, n);
        while (m--) {
            int op = read();
            if (op == 1) {
                int x = read(), y = read(), z = read();
                update_chain(x, y, z);
            } else if (op == 2) {
                int x = read(), y = read();
                write(query_chain(x, y), true);
            } else if (op == 3) {
                int x = read(), z = read();
                update_son(x, z);
            } else {
                int x = read();
                write(query_son(x), true);
            }
        }
        return 0;
    }
    

    点分治

    洛谷 P3806 【模板】点分治1

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e4 + 10);
    const int maxm(1e2 + 10);
    const int maxk(2e7 + 10);
    int ecnt, head[maxn];
    int que[maxm], ans[maxn];
    int rt, tot, root[maxn], siz[maxn], maxp[maxn];
    int cnt, tmp[maxn], dis[maxn];
    bool vis[maxn], judge[maxk];
    
    struct edge {
        int to, wt, nxt;
    } edges[maxn << 1];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline void addEdge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].wt = w;
        edges[ecnt].nxt = head[u];
        head[u] = ecnt++;
    }
    
    void getRoot(int u, int f)
    {
        siz[u] = 1;
        maxp[u] = 0;
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to;
            if (vis[v] or v == f) {
                continue;
            }
            getRoot(v, u);
            siz[u] += siz[v];
            maxp[u] = max(maxp[u], siz[v]);
        }
        maxp[u] = max(maxp[u], tot - siz[u]);
        if (maxp[u] < maxp[rt]) {
            rt = u;
        }
    }
    
    void getDis(int u, int f)
    {
        tmp[cnt++] = dis[u];
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to, w = edges[i].wt;
            if (vis[v] or v == f) {
                continue;
            }
            dis[v] = dis[u] + w;
            getDis(v, u);
        }
    }
    
    void solve(int u, int m)
    {
        static queue<int> q;
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to, w = edges[i].wt;
            if (vis[v]) {
                continue;
            }
            cnt = 0;
            dis[v] = w;
            getDis(v, u);
            for (int j = 0; j < cnt; ++j) {
                for (int k = 0; k < m; ++k) {
                    if (que[k] >= tmp[j]) {
                        ans[k] or_eq judge[que[k] - tmp[j]];
                    }
                }
            }
            for (int j = 0; j < cnt; ++j) {
                q.push(tmp[j]);
                judge[tmp[j]] = true;
            }
        }
        while (not q.empty()) {
            judge[q.front()] = false;
            q.pop();
        }
    }
    
    void divide(int u, int m)
    {
        vis[u] = judge[0] = true;
        solve(u, m);
        for (int i = head[u]; compl i; i = edges[i].nxt) {
            int v = edges[i].to;
            if (vis[v]) {
                continue;
            }
            maxp[rt = 0] = tot = siz[v];
            getRoot(v, 0);
            getRoot(rt, 0);
            divide(rt, m);
        }
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        memset(head, -1, sizeof head);
        int n = read(), m = read();
        for (int i = 0; i < n - 1; ++i) {
            int u = read(), v = read(), w = read();
            addEdge(u, v, w);
            addEdge(v, u, w);
        }
        for (int i = 0; i < m; ++i) {
            que[i] = read();
        }
        tot = maxp[0] = n;
        getRoot(1, 0);
        getRoot(rt, 0);
        divide(rt, m);
        for (int i = 0; i < m; ++i) {
            puts(ans[i] ? "AYE" : "NAY");
        }
        return 0;
    }
    

    洛谷 P3690 【模板】Link Cut Tree (动态树)

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll = long long;
    using p = pair<int, int>;
    const int maxn(1e5 + 10);
    
    struct node {
        int l, r;
        int ch[2], fa;
        int val, sum;
        bool rev;
    } tree[maxn];
    
    template<typename T = int>
    inline const T read()
    {
        T x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' or ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' and ch <= '9') {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    template<typename T>
    inline void write(T x, bool ln)
    {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10, false);
        putchar(x % 10 + '0');
        if (ln) putchar(10);
    }
    
    inline int& ls(int cur)
    {
        return tree[cur].ch[0];
    }
    
    inline int& rs(int cur)
    {
        return tree[cur].ch[1];
    }
    
    inline bool get_rel(int cur, int fa)
    {
        return tree[fa].ch[1] == cur;
    }
    
    inline void connect(int cur, int fa, bool rel)
    {
        tree[fa].ch[rel] = cur;
        tree[cur].fa = fa;
    }
    
    inline bool is_root(int cur)
    {
        return ls(tree[cur].fa) not_eq cur and rs(tree[cur].fa) not_eq cur;
    }
    
    inline void push_up(int cur)
    {
        tree[cur].sum = tree[cur].val xor tree[ls(cur)].sum xor tree[rs(cur)].sum;
    }
    
    inline void reverse(int cur)
    {
        swap(ls(cur), rs(cur));
        tree[cur].rev xor_eq 1;
    }
    
    inline void push_down(int cur)
    {
        if (tree[cur].rev) {
            reverse(ls(cur));
            reverse(rs(cur));
            tree[cur].rev = false;
        }
    }
    
    inline void rotate(int cur)
    {
        int fa = tree[cur].fa;
        int gf = tree[fa].fa;
        bool rel = get_rel(cur, fa);
        connect(tree[cur].ch[rel xor 1], fa, rel);
        tree[cur].fa = gf;
        if (not is_root(fa)) {
            tree[gf].ch[get_rel(fa, gf)] = cur;
        }
        connect(fa, cur, rel xor 1);
        push_up(fa);
        push_up(cur);
    }
    
    inline void push_all(int cur)
    {
        if (not is_root(cur)) {
            push_all(tree[cur].fa);
        }
        push_down(cur);
    }
    
    inline void splaying(int cur)
    {
        push_all(cur);
        while (not is_root(cur)) {
            int fa = tree[cur].fa;
            int gf = tree[fa].fa;
            if (not is_root(fa)) {
                get_rel(cur, fa) xor get_rel(fa, gf) ? rotate(cur) : rotate(fa);
            }
            rotate(cur);
        }
    }
    
    inline void access(int cur)
    {
        for (int pre = 0; cur; cur = tree[cur].fa) {
            splaying(cur);
            rs(cur) = pre;
            push_up(cur);
            pre = cur;
        }
    }
    
    inline void make_root(int cur)
    {
        access(cur);
        splaying(cur);
        reverse(cur);
    }
    
    inline int find_root(int cur)
    {
        access(cur);
        splaying(cur);
        while (ls(cur)) {
            push_down(cur);
            cur = ls(cur);
        }
        splaying(cur);
        return cur;
    }
    
    inline void link(int u, int v)
    {
        make_root(u);
        if (find_root(v) not_eq u) {
            tree[u].fa = v;
        }
    }
    
    inline void cut(int u, int v)
    {
        make_root(u);
        if (find_root(v) == u and tree[v].fa == u and not ls(v)) {
            rs(u) = tree[v].fa = 0;
            push_up(u);
        }
    }
    
    inline void split(int u, int v)
    {
        make_root(u);
        access(v);
        splaying(v);
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif
        int n = read(), m = read();
        for (int i = 1; i <= n; ++i) {
            tree[i].val = read();
        }
        while (m--) {
            int op = read(), x = read(), y = read();
            if (op == 0) {
                split(x, y);
                write(tree[y].sum, true);
            } else if (op == 1) {
                link(x, y);
            } else if (op == 2) {
                cut(x, y);
            } else {
                splaying(x);
                tree[x].val = y;
                push_up(x);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    【BZOJ 1579】 1579: [Usaco2009 Feb]Revamping Trails 道路升级 (最短路)
    有限广播地址与直接广播地址
    人生苦短之我用Python篇(线程/进程、threading模块:全局解释器锁gil/信号量/Event、)
    SQL基础二
    Ubuntu命令:sudo、shutdown、apt-get、vim
    SQL基础一
    MPLS基础一
    第一章 Linux系统入门
    P4简介:数据平面的编程语言
    人生苦短之我用Python篇(安装第三方库、正则表达式)
  • 原文地址:https://www.cnblogs.com/singularity2u/p/templates.html
Copyright © 2011-2022 走看看