板子们

 

单调队列——滑动窗口

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 3;

int n, k, a[maxn], mx[maxn], mi[maxn], q[maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void getmin()
{
    int h = 1, t = 0;
    for(int i=1; i<k; i++)
    {
        while(h <= t && a[q[t]] >= a[i]) t--;
        q[++t] = i;
    }
    for(int i=k; i<=n; i++)
    {
        while(q[h] <= i - k) h++;
        while(h <= t && a[q[t]] >= a[i]) t--;
        q[++t] = i; mi[i] = a[q[h]];
        //printf("mi[%d] = %d\n", i, mi[i]);
    }
}

void getmax()
{
    int h = 1, t = 0;
    for(int i=1; i<k; i++)
    {
        while(h <= t && a[q[t]] <= a[i]) t--;
        q[++t] = i;
    }
    for(int i=k; i<=n; i++)
    {
        while(q[h] <= i - k) h++;
        while(h <= t && a[q[t]] <= a[i]) t--;
        q[++t] = i; mx[i] = a[q[h]];
        //printf("mx[%d] = %d\n", i, mx[i]);
    }
}

int main()
{
    n = read(); k = read();
    for(int i=1; i<=n; i++) a[i] = read();
    getmax(); getmin();
    for(int i=k; i<=n; i++)
    {
        printf("%d ", mi[i]);
    }
    printf("\n");
    for(int i=k; i<=n; i++)
    {
        printf("%d ", mx[i]);
    }
    printf("\n");

    return 0;
}
树状数组——区间修改,区间查询
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 3;

int n, m, a[maxn];
ll c1[maxn], c2[maxn];
char op[7];

inline ll read()
{
    ll 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void add(int x, ll d)
{
    int i = x;
    while(i <= n)
    {
        c1[i] += d;
        c2[i] += x * d;//注意是x*d而不是i*d
        i += (i & -i);
    }
}

ll query(int x)
{
    ll ans = 0;
    int i = x;
    while(i > 0)
    {
        ans += (x+1)*c1[i]-c2[i];
        i -= (i & -i);//x和i是不同的,从表达式里就可以看出来
    }
    return ans;
}

int main()
{
    n = read();
    for(int i=1; i<=n; i++)
    {
        a[i] = read();
        add(i, a[i]-a[i-1]);
    }
    m = read();
    for(int i=1; i<=m; i++)
    {
        scanf("%s", op);
        if(op[0] == 'A')
        {
            int l = read(), r = read(); ll d = read();
            add(l, d); add(r+1, -d);
        }
        else 
        {
            int l = read(), r = read();
            if(l == 1) printf("%lld\n", query(r));
            else printf("%lld\n", query(r) - query(l-1));
        }
    }

    return 0;
}
二维树状数组——移动电话
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1500;

int fl, s, c[maxn][maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void add(int x, int y, int d)
{
    for(int i=x; i<=s; i+=(i&-i))
    {
        for(int j=y; j<=s; j+=(j&-j))
        {
            c[i][j] += d;
        }
    }
}

int query(int x, int y)
{
    int ans = 0;
    for(int i=x; i>0; i-=(i&-i))
    {
        for(int j=y; j>0; j-=(j&-j))
        {
            ans += c[i][j];
        }
    }
    return ans;
}

int main()
{
    fl = read(); s = read();
    fl = read();
    while(fl != 3)
    {
        if(fl == 1)
        {
            int x = read()+1, y = read()+1, d = read();
            add(x, y, d);
        }
        else if(fl == 2)
        {
            int l = read()+1, b = read()+1, k = read()+1, t = read()+1;
            int ans = query(k, t)-query(k, b-1)-query(l-1, t)+query(l-1, b-1);
            printf("%d\n", ans);
        }
        fl = read();
    }

    return 0;
}
线段树——最大值
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 3;

int n, m, a[maxn];

inline ll read()
{
    ll 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    struct tree 
    {
        int max;
    }t[maxn<<2];
    void pushup(int x)
    {
        t[x].max = max(t[x<<1].max, t[x<<1|1].max);
    }
    void build(int x, int l, int r)
    {
        if(l == r) 
        {
            t[x].max = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(x<<1, l, mid);
        build(x<<1|1, mid+1, r);
        pushup(x);
    }
    int query(int x, int l, int r, int L, int R)
    {
        if(L <= l && r <= R)
        {
            return t[x].max;
        }
        int mid = (l + r) >> 1, ans = 0;
        if(L <= mid) ans = max(ans, query(x<<1, l, mid, L, R));
        if(R > mid) ans = max(ans, query(x<<1|1, mid+1, r, L, R));
        return ans;
    }
}t;

int main()
{
    n = read();
    for(int i=1; i<=n+1; i++) a[i] = read();
    t.build(1, 1, n+1);
    m = read();
    for(int i=1; i<=m; i++)
    {
        int l = read()+1, r = read()+1;
        int ans = t.query(1, 1, n+1, l, r);
        printf("%d\n", ans);
    }

    return 0;
}
线段树——区间求和
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 3;

int n, m;
ll a[maxn];
char op[5];

inline ll read()
{
    ll 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    struct tree 
    {
        ll sum, lazy;
    }t[maxn<<2];
    void pushup(int x)
    {
        t[x].sum = t[x<<1].sum + t[x<<1|1].sum;
    }
    void pushdown(int x, int l, int r)
    {
        int ls = x<<1, rs = x<<1|1, mid = (l + r) >> 1;
        ll lz = t[x].lazy; t[x].lazy = 0;
        t[ls].lazy += lz;
        t[ls].sum += lz * (mid - l + 1);
        t[rs].lazy += lz;
        t[rs].sum += lz * (r - mid);
    }
    void build(int x, int l, int r)
    {
        if(l == r) 
        {
            t[x].sum = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(x<<1, l, mid);
        build(x<<1|1, mid+1, r);
        pushup(x);
    }
    void update(int x, int l, int r, int L, int R, ll d)
    {
        if(L <= l && r <= R)
        {
            t[x].sum += (r - l + 1) * d; t[x].lazy += d;
            return;
        }
        if(t[x].lazy) pushdown(x, l, r);
        int mid = (l + r) >> 1;
        if(L <= mid) update(x<<1, l, mid, L, R, d);
        if(R > mid) update(x<<1|1, mid+1, r, L, R, d);
        pushup(x);
    }
    ll query(int x, int l, int r, int L, int R)
    {
        if(L <= l && r <= R)
        {
            return t[x].sum;
        }
        if(t[x].lazy) pushdown(x, l, r);
        int mid = (l + r) >> 1; ll ans = 0;
        if(L <= mid) ans += query(x<<1, l, mid, L, R);
        if(R > mid) ans += query(x<<1|1, mid+1, r, L, R);
        return ans;
    }
}t;

int main()
{
    n = read();
    for(int i=1; i<=n; i++) a[i] = read();
    t.build(1, 1, n);
    m = read();
    for(int i=1; i<=m; i++)
    {
        scanf("%s", op);
        if(op[0] == 'A')
        {
            int l = read(), r = read(); ll d = read();
            t.update(1, 1, n, l, r, d);
        }
        else 
        {
            int l = read(), r = read();
            ll ans = t.query(1, 1, n, l, r);
            printf("%lld\n", ans);
        }
    }

    return 0;
}
树状数组——区间修改,单点查询
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 3;

int n, m, a[maxn];
ll c[maxn];
char op[7];

inline ll read()
{
    ll 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void add(int x, ll d)
{
    while(x <= n)
    {
        c[x] += d;
        x += (x & -x);
    }
}

ll query(int x)
{
    ll ans = 0;
    while(x > 0)
    {
        ans += c[x];
        x -= (x & -x);
    }
    return ans;
}

int main()
{
    n = read();
    for(int i=1; i<=n; i++) a[i] = read();
    add(1, a[1]);
    for(int i=2; i<=n; i++) add(i, a[i]-a[i-1]);
    m = read();
    for(int i=1; i<=m; i++)
    {
        scanf("%s", op);
        if(op[0] == 'A')
        {
            int l = read(), r = read(); ll d = read();
            add(l, d); add(r+1, -d);
        }
        else 
        {
            int p = read();
            ll ans = query(p);
            printf("%lld\n", ans);
        }
    }

    return 0;
}
HH的项链——树状数组
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 3;
const int maxm = 2e5 + 3;

int n, m, R, a[maxn], ans[maxm], las[maxn], c[maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct que 
{
    int l, r, id;
    bool operator < (const que &T) const 
    {
        return r < T.r;
    }
}q[maxm];

inline void add(int x, int d)
{
    while(x <= n)
    {
        c[x] += d;
        x += (x & -x);
    }
}

inline int query(int x)
{
    int ans = 0;
    while(x > 0)
    {
        ans += c[x];
        x -= (x & -x);
    }
    return ans;
}

int main()
{
    n = read();
    for(int i=1; i<=n; i++) a[i] = read();
    m = read();
    for(int i=1; i<=m; i++)
    {
        q[i].l = read(); q[i].r = read(); q[i].id = i;
    }
    sort(q+1, q+1+m);
    for(int i=1; i<=m; i++)
    {
        while(R < q[i].r)
        {
            R++;
            if(las[a[R]]) add(las[a[R]], -1);
            add(R, 1);
            las[a[R]] = R;
        }
        if(q[i].l == 1) ans[q[i].id] = query(R);
        else ans[q[i].id] = query(R)-query(q[i].l-1);
    }
    for(int i=1; i<=m; i++)
    {
        printf("%d\n", ans[i]);
    }

    return 0;
}
dfs序1
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 3;

int dfn[maxn], v[maxn], nt, n, m, r, siz[maxn], fnd[maxn];
ll c[maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int nxt, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].nxt = head[x];
    head[x] = len;
}

void dfs(int u, int fa)
{
    dfn[++nt] = u; fnd[u] = nt;
    siz[u] = 1;
    for(int i=head[u]; i; i=a[i].nxt)
    {
        int v = a[i].to;
        if(v == fa) continue;
        dfs(v, u);
        siz[u] += siz[v];
    }
}

void addt(int x, ll d)
{
    while(x <= n)
    {
        c[x] += d;
        x += (x & -x);
    }
}

ll query(int x)
{
    ll ans = 0;
    while(x > 0)
    {
        ans += c[x];
        x -= (x & -x);
    }
    return ans;
}

int main()
{
    n = read(); m = read(); r = read();
    for(int i=1; i<=n; i++) v[i] = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    dfs(r, 0);
    for(int i=1; i<=n; i++)
    {
        addt(i, v[dfn[i]]);
    }
    for(int i=1; i<=m; i++)
    {
        int fl = read();
        if(fl == 1)
        {
            int a = read(), x = read();
            addt(fnd[a], x);//不用dfn数组
        }
        else 
        {
            int a = read();
            ll ans = query(fnd[a]+siz[a]-1)-query(fnd[a]-1);//不用dfn数组
            printf("%lld\n", ans);
        }
    }

    return 0;
}
倍增LCA——牧场旅行
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1130;

int n, q, f[maxn][12], c[maxn][12], dep[maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int nxt, to, w;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y, int w)
{
    a[++len].to = y; a[len].nxt = head[x]; a[len].w = w;
    head[x] = len;
}

void dfs(int x, int fa)
{
    f[x][0] = fa; 
    dep[x] = dep[fa] + 1;
    for(int i=1; i<12; i++)
    {
        f[x][i] = f[f[x][i-1]][i-1];
        c[x][i] = c[f[x][i-1]][i-1] + c[x][i-1];
    }
    for(int i=head[x]; i; i=a[i].nxt)
    {
        int v = a[i].to;
        if(v == fa) continue;
        c[v][0] = a[i].w;
        dfs(v, x);
    }
}

int query(int x, int y)
{
    if(dep[x] > dep[y]) swap(x, y);
    int tmp = dep[y] - dep[x], ans = 0;
    for(int i=0; tmp; i++,tmp>>=1)
    {
        if(tmp & 1) ans += c[y][i], y = f[y][i];
    }
    if(y == x) return ans;//LCA return x;
    for(int i=11; i>=0&&x!=y; i--)
    {
        if(f[x][i] != f[y][i])
        {
            ans += c[x][i] + c[y][i];
            x = f[x][i]; y = f[y][i];//因为写成了y = c[y][i]错了3次!?
        }
    }
    ans += c[x][0] + c[y][0];
    return ans;//LCA return f[x][0]
}

int main()
{
    n = read(); q = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read(), w = read();
        add(x, y, w); add(y, x, w);
    }
    dfs(1, 0);
    for(int i=1; i<=q; i++)
    {
        int x = read(), y = read();
        printf("%d\n", query(x, y));
    }

    return 0;
}
树链剖分——路径求和+最大值
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 3e4 + 2;

int n, m, w[maxn], fa[maxn];
int dep[maxn], dfn[maxn], nt, fnd[maxn], siz[maxn], son[maxn], top[maxn];
char op[8];
ll ans;

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct edge 
{
    int nxt, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].nxt = head[x];
    head[x] = len;
}

void dfs1(int u, int fat, int depth)
{
    fa[u] = fat;
    dep[u] = depth;
    siz[u] = 1;
    son[u] = 0;
    int maxsize = 0;
    
    for(int i=head[u]; i; i=a[i].nxt)
    {
        int v = a[i].to;
        if(v == fat) continue;
        dfs1(v, u, depth+1);
        siz[u] += siz[v];
        if(siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}

void dfs2(int u, int ancestor)
{
    dfn[u] = ++nt; fnd[nt] = u;
    top[u] = ancestor;
    if(son[u])
    {
        dfs2(son[u], ancestor);
    }
    for(int i=head[u]; i; i=a[i].nxt)
    {
        int v = a[i].to;
        if(v == fa[u] || v == son[u]) continue;
        dfs2(v, v);
    }
}

struct node 
{
    struct tree 
    {
        int max; ll sum;
    }t[maxn<<2];
    void pushup(int x)
    {
        t[x].max = max(t[x<<1].max, t[x<<1|1].max);
        t[x].sum = t[x<<1].sum + t[x<<1|1].sum;
    }
    void build(int x, int l, int r)
    {
        if(l == r)
        {
            t[x].max = t[x].sum = w[fnd[l]];
            return;
        }
        int mid = (l + r) >> 1;
        build(x<<1, l, mid);
        build(x<<1|1, mid+1, r);
        pushup(x);
    }
    void update(int x, int l, int r, int p, int v)
    {
        if(l == r)
        {
            t[x].max = t[x].sum = v;
            return;
        }
        int mid = (l + r) >> 1;
        if(p <= mid) update(x<<1, l, mid, p, v);
        else update(x<<1|1, mid+1, r, p, v);
        pushup(x);
    }
    int querymax(int x, int l, int r, int L, int R)
    {
        if(L <= l && r <= R)
        {
            return t[x].max;
        }
        int mid = (l + r) >> 1, ans = -1e9;
        if(L <= mid) ans = querymax(x<<1, l, mid, L, R);
        if(R > mid) ans = max(ans, querymax(x<<1|1, mid+1, r, L, R));
        return ans;
    }
    ll querysum(int x, int l, int r, int L, int R)
    {
        if(L <= l && r <= R)
        {
            return t[x].sum;
        }
        int mid = (l + r) >> 1; ll ans = 0;
        if(L <= mid) ans = querysum(x<<1, l, mid, L, R);
        if(R > mid) ans += querysum(x<<1|1, mid+1, r, L, R);
        return ans;
    }
}t;

int querymax(int x, int y)
{
    int ans = -1e9;
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        ans = max(ans, t.querymax(1, 1, n, dfn[top[x]], dfn[x]));
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    ans = max(ans, t.querymax(1, 1, n, dfn[x], dfn[y]));
    return ans; 
}

ll querysum(int x, int y)
{
    ll ans = 0;
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += t.querysum(1, 1, n, dfn[top[x]], dfn[x]);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    ans += t.querysum(1, 1, n, dfn[x], dfn[y]);
    return ans;
}

int main()
{
    n = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    dfs1(1, 1, 1);
    dfs2(1, 1);
    for(int i=1; i<=n; i++) w[i] = read();
    t.build(1, 1, n);
    m = read();
    while(m--)
    {
        scanf("%s", op);
        if(op[0] == 'C')
        {
            int x = read(), d = read();
            t.update(1, 1, n, dfn[x], d);
        }
        else if(op[1] == 'M')
        {
            int l = read(), r = read();
            ans = querymax(l, r);
            printf("%lld\n", ans);
        }
        else 
        {
            int l = read(), r = read();
            ans = querysum(l, r);
            printf("%lld\n", ans);
        }
    }
    
    return 0;
}
正反图Spfa——奶牛派对
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1303;
const int M = 1e6 + 2;

int n, m, q, dis[maxn][2], ans;
bool vis[maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct edge 
{
    int nxt, to, w;
}a[M][2];
int head[maxn][2], len[2];

void add(int x, int y, int w, int c)
{
    a[++len[c]][c].to = y; a[len[c]][c].nxt = head[x][c]; a[len[c]][c].w = w;
    head[x][c] = len[c];
}

queue<int> que;

void spfa(int s, int c)
{
    memset(vis, 0, sizeof(vis));
    que.push(s);
    vis[s] = 1;
    dis[s][c] = 0;
    while(!que.empty())
    {
        int x = que.front(); que.pop();
        vis[x] = 0;
        for(int i=head[x][c]; i; i=a[i][c].nxt)
        {
            int y = a[i][c].to;
            if(dis[y][c] > dis[x][c] + a[i][c].w)
            {
                dis[y][c] = dis[x][c] + a[i][c].w;
                if(!vis[y])
                {
                    que.push(y);
                }
            }
        }
    }
}

int main()
{
    n = read(); m = read(); q = read();
    for(int i=1; i<=m; i++)
    {
        int x = read(), y = read(), w = read();
        add(x, y, w, 0); add(y, x, w, 1);
    }
    memset(dis, 0x3f, sizeof(dis));
    spfa(q, 0); spfa(q, 1);
    for(int i=1; i<=n; i++)
    {
        ans = max(ans, dis[i][0] + dis[i][1]);
    }
    printf("%d\n", ans);
    
    return 0;
}
带权并查集——银河英雄传说
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 3e4 + 4;

int T, fa[maxn], fnt[maxn], num[maxn];
char op[3];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int find(int x)
{
    if(x == fa[x]) return x;
    //else return fa[x] = find(fa[x]);
    int fx = find(fa[x]);
    fnt[x] += fnt[fa[x]];//not fx,一次只跳一步
    fa[x] = fx;
    return fa[x];
}

int main()
{
    T = read();
    for(int i=1; i<=30000; i++)
    {
        fa[i] = i; num[i] = 1; fnt[i] = 0;
    }
    while(T--)
    {
        scanf("%s", op);
        int x = read(), y = read();
        int fx = find(x), fy = find(y);
        if(op[0] == 'M')
        {
            fnt[fx] += num[fy];
            num[fy] += num[fx];
            num[fx] = 0;
            fa[fx] = fy;
        }
        else 
        {
            if(fx != fy) printf("-1\n");
            else printf("%d\n", abs(fnt[x]-fnt[y])-1);
        }
    }
    
    return 0;
}
RMQ_ST表
void RMQ_init()
{
    for(int i=1; i<=n; i++) d[i][0] = a[i];
    for(int j=1; (1<<j)<=n; j++)
    {
        for(int i=1; i+(1<<j)-1<=n; i++)
        {
            d[i][j] = min(d[i][j-1], d[i+(1<<(j-1))][j-1]);
        }
    }
}

int RMQ(int L, int R)
{
    int k = 0;
    while((1<<(k+1)) <= R-L+1) k++;
    return min(d[L][k], d[R-(1<<k)+1][k]);
}
tarjan缩点(有向图的强连通分量)
 void tarjan(int x)
{
    dfn[x] = low[x] = ++num;
    stk.push(x);
    v[x] = 1;
    vis[x] = 1;
    for(int i=head[x]; i; i=a[i].nxt)
    {
        if(!dfn[a[i].to])
        {
            tarjan(a[i].to);
            low[x] = min(low[x], low[a[i].to]);
        }
        else if(v[a[i].to])
        {
            low[x] = min(low[x], dfn[a[i].to]);
        }
    }
    if(low[x] == dfn[x])
    {
        int y, tot = 0;
        ++t;
        do 
        {
            y = stk.top();
            stk.pop();
            v[y] = 0;
            belong[y] = t;
            tot++;
        }while(y != x);
        if(tot > 1) ans = min(ans, tot);
    }
}
tarjan求割点(无向图)
 void tarjan(int x)
{
    dfn[x] = low[x] = ++num;
    int son = 0;
    for(int i=head[x]; i; i=a[i].nxt)
    {
        if(!dfn[a[i].to])
        {
            son++;
            tarjan(a[i].to);
            low[x] = min(low[x], low[a[i].to]);
            if(dfn[x] <= low[a[i].to])
            {
                if(x != root || son > 1) cut[x] = true;
            }
        }
        else 
        {
            low[x] = min(low[x], dfn[a[i].to]);
        }
    }
}
tarjan求割边(无向图)
 void tarjan(int now, int fa)
{
    dfn[now] = low[now] = ++num;
    bool first = true;
    for(int i=head[now]; i; i=a[i].nxt)
    {
        if(first && a[i].to == fa)//first不是没有用,它管跳过第一次,考虑重边了
        {
            first  = false;
            continue;
        }
        if(!dfn[to[i]])
        {
            tarjan(to[i]);
            low[now] = min(low[now], low[a[i].to]);
            if(dfn[now] < dfn[a[i].to])
            {
                cnt++;
                cut[i] = cut[i^1] = true;
            }
        }
        else 
        {
            low[now] = min(low[now], dfn[a[i].to]);
        }
    }
}
tarjan点双连通(无向图)
 void tarjan(int now, int fa)
{
    vis[now] = true;
    dfn[now] = low[now] = ++dfs_clock;
    stk[++top] = now;

    bool first = true;
    int son = 0;
    for(int i=head[now]; i; i=a[i].nxt)
    {
        int to = a[i].to;
        if(first && to == fa)
        {
            first = false;
            continue;
        }
        if(!dfn[to])
        {
            son++;
            tarjan(to, now);
            low[now] = min(low[now], low[to]);
            if(dfn[now] <= low[to])
            {
                cut[now] = true;
                cnt++;
                dslt[cnt].push_back(now);//既然不出栈就提前放进去
                int x;
                do 
                {
                    x = stk[top--];
                    dslt[cnt].push_back(x);
                }while(x != to);//now不能直接出栈,它有可能属于多个点双
            }
        }
        else 
        {
            low[now] = min(low[now], dfn[to]);
        }
    }
    if(fa == -1 && son == 1) cut[now] = false;
}
Tarjan边双联通(无向图)
 void tarjan(int now, int eid)
{
    vis[now] = true;
    dfn[now] = low[now] = ++dfs_clock;
    stk[++top] = now;

    for(int i=head[now]; i; i=a[i].nxt)
    {
        int to = a[i].to;
        int id = a[i].id;
        if(id == eid^1) continue;

        if(!dfn[to])
        {
            tarjan(to, id);
            low[now] = min(low[now], low[to]);
        }
        else 
        {
            low[now] = min(low[now], dfn[to]);
        }
    }
    if(dfn[now] == low[now])
    {
        cut[eid] = true;
        cnt++;
        int x;
        do 
        {
            x = stk[top--];
            bslt[cnt].push_back(x);
        }while(x != now);
    }
}
二分图
 bool dfs(int x)
{
    for(int i=1; i<=n; i++)
    {
        if(!vis[i] && mp[x][i])
        {
            vis[i] = 1;
            if(match[i] == 0 || dfs(match[i]))
            {
                match[i] = x;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    n = read(); k = read();
    for(int i=1; i<=k; i++)
    {
        int x = read(), y = read();
        mp[x][y] = 1;
    }
    for(int i=1; i<=n; i++)
    {
        memset(vis, 0, sizeof(vis));
        if(dfs(i)) ans++;
    }
    printf("%d", ans);

    return 0;
}
重载运算符
 struct node 
{
    int r;
    bool operator < (const node &a) const 
    {
        return r < a.r;//return r > a.r;优先队列小的优先出队
    }
}p[maxn];
//如果使用sort得到按照r从小到大排序的p
//优先队列是相反的
lazy
 #include<bits/stdc++.h>
using namespace std;

#define maxn 100000
#define lson (rt << 1)
#define rson (rt << 1 | 1)
long long n, m, a[maxn], u, t, v, ans;
char s[7];

struct node
{
    long long l, r, sum, lazy;//结构体里的数据类型别忘了改!
};
node tree[maxn * 4];

long long read()
{
    long long x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1)+ (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}


void pushup(long long rt)
{
    tree[rt].sum = tree[lson].sum + tree[rson].sum;
    //tree[rt].min = min(tree[lson].min, tree[rson].min);
}

void build(long long rt, long long l, long long r)
{
    tree[rt].l = l;
    tree[rt].r = r;
    if(l == r)
    {
        tree[rt].sum = a[l];
        return;
    }
    long long mid = (l + r) >> 1;
    build(lson, l, mid);
    build(rson, mid+1, r);

    pushup(rt);
}

void pushdown(long long rt)
{
    if(tree[rt].lazy)
    {
        long long lz = tree[rt].lazy;
        tree[rt].lazy = 0;
        tree[lson].lazy += lz;
        tree[rson].lazy += lz;
        tree[lson].sum += lz * (tree[lson].r - tree[lson].l + 1);
        tree[rson].sum += lz * (tree[rson].r - tree[rson].l + 1);
    }
}

void update(long long rt, long long l, long long r, long long val)
{
    if(l <= tree[rt].l && tree[rt].r <= r)
    {
        tree[rt].lazy += val;
        tree[rt].sum += val * (tree[rt].r - tree[rt].l + 1);
        return;
    }
    pushdown(rt);
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(l <= mid) update(lson, l, r, val);
    if(r > mid) update(rson, l, r, val);
    pushup(rt);
}

long long query(long long rt, long long l, long long r)
{
    if(l <= tree[rt].l && tree[rt].r <= r)
    {
        return tree[rt].sum;
    }
    pushdown(rt);
    long long mid = (tree[rt].l + tree[rt].r) >> 1;
    long long val = 0;
    if(l <= mid) val += query(lson, l, r);
    if(r > mid) val += query(rson, l, r);
    return val;
}

/*void update(int rt, int pos, int val)
{
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].sum += val;
        tree[rt].min += val;
        return;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(pos <= mid) update(lson, pos, val);
    else update(rson, pos, val);

    pushup(rt);
}*/

/*int query(int rt, int l, int r)
{
    if(l <= tree[rt].l && tree[rt].r <= r)
    {
        return tree[rt].sum;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;

    if(r <= mid) return query(lson, l, r);
    else if(l > mid) return query(rson, l, r);
    else return (query(lson, l, r) + query(rson, l, r));
}*/

/*int monn(int rt, int l, int r)
{
    if(l <= tree[rt].l && tree[rt].r <= r)
    {
        return tree[rt].min;
    }
    int mid = (tree[rt].l + tree[rt].r) >> 1;

    int mi = 0x7fffffff;
    if(l <= mid) mi = min(mi, monn(lson, l ,r));
    if(r > mid) mi = min(mi, monn(rson, l, r));
    return mi;
}*/

int main()
{
    n = read();
    if(n == 0) exit(0);
    for(int i=1; i<=n; i++)
    {
        a[i] = read();
    }
    build(1, 1, n);
    m = read();
    for(int i=1; i<=m; i++)
    {
        scanf("%s", s);
        u = read();
        if(s[0] == 'A')
        {
            t = read();
            v = read();
            update(1, u, t, v);
        }
        if(s[0] == 'Q')
        {
            ans = query(1, u, u);
            printf("%lld\n", ans);
        }
    }
}
混合背包
 #include<iostream>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<queue>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cstdio>
#include<deque>
#include<bitset>
using namespace std;

#define maxn 300000
int n, m;
int f[maxn], c[maxn];
int v[maxn], p[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{
    m = read(); n =read();
    for(int i=1; i<=n; i++)
    {
        v[i] = read();
        c[i] = read();
        p[i] = read();
    }
    for(int i=1; i<=n; i++)
    {
        if(p[i] == 0)
        {
            for(int j=v[i]; j<=m; j++)
            {
                f[j] = max(f[j], f[j-v[i]]+c[i]);
            }
        }
        else
        {
            for(int k=1; k<=p[i]; k<<=1)
            {
                for(int j=m; j>=v[i]*k; j--)
                {
                    f[j] = max(f[j], f[j-v[i]*k]+c[i]*k);
                }
                p[i] -= k;
            }
            if(p[i])
            {
                for(int j=m; j>=v[i]*p[i]; j--)
                {
                    f[j] = max(f[j], f[j-v[i]*p[i]]+c[i]*p[i]);
                }
            }
        }
    }
    printf("%d", f[m]);

    return 0;
}
Hash
#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ll;
const int maxn = 1e6 + 7;
const int M = 998244353;
const int B = 233;

char w[maxn], t[maxn];
int n, len1, len2, ans;
ll h1, f[maxn], p[maxn], h2;

int main()
{
    p[0] = 1;
    for(int i=1; i<=10000; i++)
    {
        p[i] = p[i-1] * B;
    }
    scanf("%d", &n);
    while(n--)
    {
        ans = 0; h1 = 0;
        memset(f, 0, sizeof(f));

        scanf("%s%s", w, t);
        len1 = strlen(w);
        len2 = strlen(t);

        for(int i=0; i<len1; i++)
        {
            h1 = h1 * B + w[i];
        }
        f[0] = t[0];
        for(int i=1; i<len2; i++)
        {
            f[i] = f[i-1] * B + t[i];
        }
        h2 = f[len1-1];
        if(h1 == h2) ans++;
        for(int i=1; i+len1-1<len2; i++)
        {
            h2 = f[i+len1-1] - f[i-1]*p[len1];
            if(h1 == h2) ans++;
        }
        printf("%d\n",ans);
    }

    return 0;
}
KMP
 int main()
{
    //找到b在a中出现的所有位置
    scanf("%s%s", a+1, b+1);
    int la = strlen(a+1), lb = strlen(b+1);
    int j = 0;
    p[1] = 0;
    for(int i=2; i<=lb; i++)
    {
        while(j > 0 && b[i] != b[j+1]) j = p[j];
        if(b[i] == b[j+1]) j++;
        p[i] = j;
    }
    j = 0;
    for(int i=1; i<=la; i++)
    {
        while(j > 0 && a[i] != b[j+1]) j = p[j];
        if(a[i] == b[j+1]) j++;
        if(j == lb) printf("%d\n", i-lb+1), j = p[j];
    }
    
    return 0;
}
Trie
 int n, m, ch[maxn*50][26], tag[N], tot=1;

int main()
{
    scanf("%d", &n);
    for(int i=1; i<=n; i++)
    {
        scanf("%s", s+1);
        int u = 1;
        for(int j=1; s[j]; j++)
        {
            int c = s[j] - 'a';
            if(!ch[u][c]) ch[u][c] = ++tot;
            u = ch[u][c];
        }
        tag[u] = 1;
    }
    scanf("%d", &m);
    while(m--)
    {
        scanf("%s", s+1);
        int u = 1;
        for(int j=1; s[j]; j++)
        {
            int c = s[j] - 'a';
            u = ch[u][c];
            if(!u) break;
        }
        if(tag[u] == 1)
        {
            tag[u] = 2;
            printf("OK\n");
        }
        else if(tag[u] == 2)
        {
            printf("REPEAT\n");
        }
        else 
        {
            printf("WRONG\n");
        }
    }
    
    return 0;
}
矩阵乘法--发展结果
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 5;
const int mod = 998244353;

ll a1, b, c, d, n;
//int n;

struct Matrix
{
    //int a1, b, c, d;
    ll a[N][N] = {
        {1, a1, 0, 0, a1},
        {0, b, 1, 0, b},
        {0, c, 0, 1, c},
        {0, d, 0, 0, d},
        {0, 0, 0, 0, 1}
    };
}tmp;
Matrix clear()
{
    Matrix res;
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            res.a[i][j] = 0;
        }
    }
    return res;
}
Matrix init()
{
    Matrix res = clear();
    for(int i=0; i<N; i++)
    {
        res.a[i][i] = 1;
    }
    return res;
}
Matrix operator *(Matrix x, Matrix y)
{
    Matrix res = clear();
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            for(int k=0; k<N; k++)
            {
                res.a[i][j] = (res.a[i][j]+(ll)x.a[i][k]*y.a[k][j]%mod)%mod;
            }
        }
    }
    return res;
}
Matrix power(Matrix a, ll b)
{
    Matrix res = init();
    while(b)
    {
        if(b & 1) res = res * a;
        a = a * a;
        b >>= 1;
        /*for(int i=0; i<N; i++)
        {
            for(int j=0; j<N; j++)
            {
                printf("%d ", res.a[i][j]);
            }
            printf("\n");
        }*/
    }
    return res;
}
/*void print(Matrix t){
    for(int i=0;i<N;++i)
        for(int j=0;j<N;++j)
            printf("%d%c",t.a[i][j]," \n"[j==N-1]);
}*/
int main()
{
    scanf("%lld%lld%lld%d%lld", &a1, &b, &c, &d, &n);
    tmp.a[0][1] = a1; tmp.a[0][4] = a1;
    tmp.a[1][1] = b; tmp.a[1][4] = b;
    tmp.a[2][1] = c; tmp.a[2][4] = c;
    tmp.a[3][1] = d; tmp.a[3][4] = d;

    Matrix t = power(tmp, n-1);
    //f1 f1 non non f1 初始 1 1 0 0 1

    ll ans = (t.a[0][4]+t.a[1][4]+t.a[4][4])%mod;
    /*for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            printf("%d ", t.a[i][j]);
        }
        printf("\n");
    }*/
    printf("%lld", ans);

    return 0;
}
类似数位DP的分类讨论
int query(int x, int lim)
{
    int sum = 0, ans = 1;
    int cnt[32] = {0};
    for(int i=0; i<30; i++) cnt[i+1] = cnt[i] + (x>>i&1);
    //在第i位更低位有几个1,不包括第i位
    for(int i=30; i>=0; i--)
    {
        int t = x >> i & 1;
        if(!t) continue;
        int tmp = sum + (1 << i);
        if(tmp > lim) continue;
        /*
        每一次加上把这一位填0的情况数,然后把这一位填上1再往下
        如果这一位本来不能填1,那就留待以后再算,每次加上的都是以后不再考虑的
        所以和这一位有关的以后不考虑的情况已经加上了,这一位已经填好了
        就像这一位从一开始就不一样
        */
        sum = tmp; ans = (ans + (1<<cnt[i])) % mod;
        /*
        就算后来的位不会再有1,现在填上0的这一种情况也需要记录,因为接下来这一位就填上1了
        那么我填这么多1的情况怎么计算啊……
        */
    }
    return ans;
}
卡特兰数(包括递推组合数)--绳子游戏
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e5 + 5;
const ll mod = 1e9 + 7;
const int INF = 0x7ffffff;

int n, typ, mub[maxn], inv[maxn], f[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int qpow(int a, int b)
{
    int ans = 1;
    while(b)
    {
        if(b & 1) ans = ans*1ll*a%mod;
        a = a*1ll*a%mod;
        b >>= 1;
    }
    return ans;
}

int C(int n, int m)
{
    if(n < m) return 0;
    return mub[n]*1ll*inv[m]%mod*inv[n-m]%mod;
}

void init()
{
    mub[0] = 1;
    for(int i=1; i<maxn; i++) mub[i] = mub[i-1]*1ll*i%mod;
    //for(int i=1; i<maxn; i++) printf("mub[%d] = %d\n", i, mub[i]);
    inv[maxn-1] = qpow(mub[maxn-1], mod-2);
    //printf("%d\n", inv[maxn-1]);
    for(int i=maxn-1; i>=1; i--) inv[i-1] = inv[i]*1ll*i%mod;
}

int catalan(int n)
{
    return C(n*2, n)*1ll*qpow(n+1, mod-2)%mod;
}

int main()
{
    init();
    n = read(); 
    printf("%d", catalan(n));
    
    return 0;
}
AC自动机
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 6;
const int mod = 1e9 + 7;
const int INF = 2147483647;

int n, T;
char s[maxn];

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

namespace AC
{
    int tr[maxn][26], tot;
    int e[maxn], fail[maxn];

    void insert(char *s)
    {
        int u = 0;
        for(int i=1; s[i]; i++)
        {
            if(!tr[u][s[i]-'a'])
            {
                tr[u][s[i]-'a'] = ++tot;
            }
            u = tr[u][s[i]-'a'];
        }
        e[u]++;
    }

    queue<int> q;

    void build()
    {
        for(int i=0; i<26; i++)
        {
            if(tr[0][i]) q.push(tr[0][i]);
        }
        while(q.size())
        {
            int u = q.front(); q.pop();
            for(int i=0; i<26; i++)
            {
                if(tr[u][i])
                {
                    fail[tr[u][i]] = tr[fail[u]][i];
                    q.push(tr[u][i]);
                }
                else 
                {
                    tr[u][i] = tr[fail[u]][i];
                }
            }
        }
    }

    int query(char *t)
    {
        int u = 0, res = 0;
        for(int i=1; t[i]; i++)
        {
            u = tr[u][t[i]-'a'];
            for(int j=u; j && e[j]!=-1; j=fail[j])
            {
                res += e[j], e[j] = -1;
            }
        }
        return res;
    }

    void clear() 
    {
        tot = 0;
        memset(e, 0, sizeof(e));
        memset(fail, 0, sizeof(fail));
    }
}

int main()
{
    T = read();
    while(T--)
    {
        AC::clear();
        n = read();
        for(int i=1; i<=n; i++)
        {
            scanf("%s", s+1); AC::insert(s);
        }
        scanf("%s", s+1);
        AC::build();
        printf("%d", AC::query(s));
    }
    
    return 0;
}
哈希加链表存储整数(非字符串)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e6 + 3;
const int p = 13331;

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int e[maxn], nxt[maxn], h[p], n, len;

int main()
{
    n = read();
    memset(h, -1, sizeof(h));
    for(int i=1; i<=n; i++)
    {
        int o = read(), a = read();
        if(o == 1)
        {
            nxt[++len] = h[a%p]; h[a%p] = len; e[len] = a;
        }
        else if(o == 2)
        {
            int op = 0, j = h[a%p];
            while(j != -1)
            {
                //printf("e[%d] = %d\n", j, e[j]);
                if(e[j] == a) {op = 1; break;}
                j = nxt[j];
            }
            if(op) printf("Yes\n");
            else printf("No\n");
        }
        else if(o == 3)
        {
            int j = h[a%p];
            //printf("cmp h[%d] -> %d\n", a%p, nxt[j]);
            if(e[j] == a) h[a%p] = nxt[h[a%p]];
            else while(j != -1)
            {
                if(nxt[j] != -1 && e[nxt[j]] == a)
                {
                    nxt[j] = nxt[nxt[j]]; 
                    //printf("nxt[%d] = %d\n", j, nxt[nxt[j]]);
                }
                j = nxt[j];
            }
        }
    }

    return 0;
}
主席树(可持久化线段树)--区间k小
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 3;

int n, m, a[maxn], b[maxn], rt[maxn], cnt, ans;

inline int read()
{
    int 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 << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct seg 
{
    struct node 
    {
        int sum;
    }t[maxn<<5];
    int lc[maxn<<5], rc[maxn<<5], tot;
    void build(int &x, int l, int r)
    {
        x = ++tot;
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(lc[x], l, mid);
        build(rc[x], mid+1, r);
    }
    void update(int &x, int pre, int l, int r, int pos)
    {
        x = ++tot; lc[x] = lc[pre]; rc[x] = rc[pre];
        t[x].sum = t[pre].sum + 1;
        if(l == r) return;
        int mid = (l + r) >> 1;
        if(pos <= mid) update(lc[x], lc[x], l, mid, pos);
        else update(rc[x], rc[x], mid+1, r, pos);
    }
    int query(int pre, int x, int l, int r, int k)
    {
        if(l == r) return l;
        int mid = (l + r) >> 1;
        int res = t[lc[x]].sum - t[lc[pre]].sum;
        if(res >= k) return query(lc[pre], lc[x], l, mid, k);
        else return query(rc[pre], rc[x], mid+1, r, k-res);
    }
}t;

int main()
{
    n = read(); m = read();
    for(int i=1; i<=n; i++)
    {
        a[i] = read(); b[i] = a[i];
    }
    sort(b+1, b+1+n);
    cnt = unique(b+1, b+1+n)-b-1;
    t.build(rt[0], 1, cnt);
    for(int i=1; i<=n; i++)
    {
        int x = lower_bound(b+1, b+1+cnt, a[i])-b;
        t.update(rt[i], rt[i-1], 1, cnt, x);
    }
    while(m--)
    {
        int l = read(), r = read(), k = read();
        ans = t.query(rt[l-1], rt[r], 1, cnt, k);
        printf("%d\n", b[ans]);
    }
    

    return 0;
}
Treap
#include <bits/stdc++.h>

using namespace std;

const int SIZE = 100010;

struct Treap
{
    int l, r;
    int val, dat;
    int cnt, size;
}a[SIZE];
int tot, root, n, INF = 0x7fffffff;

int New(int val)
{
    a[++tot].val = val;
    a[tot].dat = rand();
    a[tot].cnt = a[tot].size = 1;
    return tot;
}

void Update(int p)
{
    a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
}

void Build()
{
    New(-INF), New(INF);
    root = 1, a[1].r = 2;
    Update(root);
}

int GetRankByVal(int p, int val)
{
    if(p == 0) return 1;//
    if(val == a[p].val) return a[a[p].l].size + 1;
    if(val < a[p].val) return GetRankByVal(a[p].l, val);
    return GetRankByVal(a[p].r, val) + a[a[p].l].size + a[p].cnt;
}

int GetValByRank(int p, int rank)
{
    if(p == 0) return INF;
    if(a[a[p].l].size >= rank) return GetValByRank(a[p].l, rank);
    if(a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
    return GetValByRank(a[p].r, rank - a[a[p].l].size - a[p].cnt);
}

void zig(int &p)
{
    int q = a[p].l;
    a[p].l = a[q].r, a[q].r = p, p = q;
    Update(a[p].r), Update(p);
}

void zag(int &p)
{
    int q = a[p].r;
    a[p].r = a[q].l, a[q].l = p, p = q;
    Update(a[p].l), Update(p);
}

void Insert(int &p, int val)
{
    if(p == 0)
    {
        p = New(val);
        return;
    }
    if(val == a[p].val)
    {
        a[p].cnt++, Update(p);
        return;
    }
    if(val < a[p].val)
    {
        Insert(a[p].l, val);
        if(a[p].dat < a[a[p].l].dat) zig(p);
    }
    else
    {
        Insert(a[p].r, val);
        if(a[p].dat < a[a[p].r].dat) zag(p);
    }
    Update(p);
}

int GetPre(int val)
{
    int ans = 1;
    int p = root;
    while(p)
    {
        if(val == a[p].val)
        {
            if(a[p].l > 0)
            {
                p = a[p].l;
                while(a[p].r > 0) p = a[p].r;
                ans = p;
            }
            break;
        }
        if(a[p].val < val && a[p].val > a[ans].val) ans = p;
        p = val < a[p].val ? a[p].l : a[p].r;
    }
    return a[ans].val;
}

int GetNext(int val)
{
    int ans = 2;
    int p = root;
    while(p)
    {
        if(val == a[p].val)
        {
            if(a[p].r > 0)
            {
                p = a[p].r;
                while(a[p].l > 0) p = a[p].l;
                ans = p;
            }
            break;
        }
        if(a[p].val > val && a[p].val < a[ans].val) ans = p;
        p = val < a[p].val ? a[p].l : a[p].r;
    }
    return a[ans].val;
}

void Remove(int &p, int val)
{
    if(p == 0) return;
    if(val == a[p].val)
    {
        if(a[p].cnt > 1)
        {
            a[p].cnt--, Update(p);
            return;
        }
        if(a[p].l || a[p].r)
        {
            if(a[p].r == 0 || a[a[p].l].dat > a[a[p].r].dat)
            {
                zig(p), Remove(a[p].r, val);
            }
            else
            {
                zag(p), Remove(a[p].l, val);
            }
            Update(p);
        }
        else p = 0;
        return;
    }
    val < a[p].val ? Remove(a[p].l, val) : Remove(a[p].r, val);
    Update(p);
}

int main()
{
    //freopen("1.txt", "r", stdin);

    Build();
    scanf("%d", &n);
    while(n--)
    {
        int opt, x;
        scanf("%d%d", &opt, &x);
        if(opt == 1)
        {
            Insert(root, x);
        }
        else if(opt == 2)
        {
            Remove(root, x);
        }
        else if(opt == 3)
        {
            //printf("last = %d\n", GetPre(x));
            printf("%d\n", GetRankByVal(root, x)-1);
        }
        else if(opt == 4)
        {
            printf("%d\n", GetValByRank(root, x+1));
        }
        else if(opt == 5)
        {
            printf("%d\n", GetPre(x));
        }
        else if(opt == 6)
        {
            printf("%d\n", GetNext(x));
        }
    }

    return 0;
}

最近开始复习了,或许以后还会继续用这个平台记录一些题。曾经卷来卷去死记硬背怎么都记不住的那些板子,不知道为什么这一遍忽然理解了,当我终于有了一篇记录板子的blog时已经不再需要背,当我终于看清楚了一点点OI的面目,我已经离开这篇乐土很久了……

感觉大学生活总体上是比高中幸福的,但是在hzoi的回忆,却一次又一次让我幻想重来,就好像如果这样,我当年就不会走得那么早,就好像如果我的时间永远定格在那些日子里的任意一天,都值得让我放弃之后所有的可能性,嗯,我太恋旧了,这是弱点。

在整个大学大一范围内找不到一个能和我一起讨论编程的女生,不在高处,却不胜寂寞,好在找到陪我玩第5人格的搭子还是很容易的。

关于上一篇博客使用了某些专有名词和专有图片,我狡辩,我不玩原神(虽然有账号),因为不知道怎么在这个游戏里活下去,不是被反派制裁就是在被反派制裁的路上,我太菜了。

posted @ 2024-11-04 21:02  Catherine_leah  阅读(55)  评论(3)    收藏  举报
/* */