ACM-ICPC竞赛积累的一些模板

写在前面

或许你可以在我的hexo博客里找到一些证明
退役了,整理一下自己的板子,菜狗队不配花里胡哨的板子

数据结构

动态主席树

const int MAXN = 2e5 + 10;
typedef long long ll;
#define ls(p) tree[p].lson
#define rs(p) tree[p].rson
struct node {
    int v;
    int lson, rson;
} tree[MAXN * 600];
int root[MAXN], tot;
int zz, yy, z[MAXN], y[MAXN];

int lowbit(int x)
{
    return -x & x;
}
void update(int& p, int pos, int l, int r, int k)
{
    if (!p)
        p = ++tot;
    tree[p].v += k;
    if (l >= r)
        return;
    int mid = (l + r) >> 1;
    (pos <= mid ? (update(ls(p), pos, l, mid, k)) : (update(rs(p), pos, mid + 1, r, k)));
}
void add(int x, int pos, int n, int k)
{
    for (; x <= n; x += lowbit(x))
        update(root[x], pos, 1, n, k);
}
int query(int l, int r, int k)
{
    if (l >= r)
        return l;
    int mid = (l + r) >> 1, num = 0;
    for (int i = 1; i <= yy; i++)
        num -= tree[ls(y[i])].v;
    for (int i = 1; i <= zz; i++)
        num += tree[ls(z[i])].v;
    if (k <= num) {
        for (int i = 1; i <= yy; i++)
            y[i] = ls(y[i]);
        for (int i = 1; i <= zz; i++)
            z[i] = ls(z[i]);
        return query(l, mid, k);
    } else {
        for (int i = 1; i <= yy; i++)
            y[i] = rs(y[i]);
        for (int i = 1; i <= zz; i++)
            z[i] = rs(z[i]);
        return query(mid + 1, r, k - num);
    }
}
int mp[MAXN], a[MAXN], b[MAXN];
struct qu {
    char tp;
    int x, y, z;
} ttp[MAXN];

int main()
{
    //freopen("txt.txt", "w", stdout);
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        b[i] = a[i];
    }
    int m = n;
    for (int i = 0; i < q; i++) {
        cin >> ttp[i].tp >> ttp[i].x >> ttp[i].y;
        if (ttp[i].tp == 'Q')
            cin >> ttp[i].z;
        else
            b[++m] = ttp[i].y;
    }
    sort(b + 1, b + m + 1);
    m = unique(b + 1, b + m + 1) - b - 1;
    for (int i = 1; i <= n; i++) {
        int pos = lower_bound(b + 1, b + m + 1, a[i]) - b;
        add(i, pos, m, 1);
    }
    for (int i = 0; i < q; i++) {
        if (ttp[i].tp == 'Q') {
            yy = zz = 0;
            for (int x = ttp[i].x - 1; x > 0; x -= lowbit(x))
                y[++yy] = root[x];
            for (int x = ttp[i].y; x > 0; x -= lowbit(x))
                z[++zz] = root[x];
            cout << b[query(1, m, ttp[i].z)] << endl;
        } else {
            int pos = lower_bound(b + 1, b + m + 1, a[ttp[i].x]) - b;
            add(ttp[i].x, pos, m, -1);
            a[ttp[i].x] = ttp[i].y;
            pos = lower_bound(b + 1, b + m + 1, ttp[i].y) - b;
            add(ttp[i].x, pos, m, 1);
        }
    }
    return 0;
}

二分

int lowerbound(int *array, int size, int key, int lazy)
{
	int first = 0, middle;
	int half, len;
	len = size;
	while (len > 0) {
		half = len >> 1;
		middle = first + half;
		if (array[middle] + lazy < key) {
			first = middle + 1;
			len = len - half - 1;
		}
		else
			len = half;
	}
	return first;
}

高精度

用的kuangbin的板子

#define MAXN 9999
#define DLEN 4
#define MAXSIZE 5010

using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAX = 1e5 + 10;
const double PI = acos(-1.0);
//10000

class BigNum {
private:
	int a[MAXSIZE];
	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 BigNum &)const;
	BigNum operator /(const int &)const;
	BigNum operator ^(const int &)const;
	long long operator %(const long long &)const;
	bool operator >(const BigNum&i_T)const;
	bool operator >(const int &i_T)const;
	void copy(int str, int end, const BigNum &);
	void print();
};

void BigNum::copy(int str, int end, const BigNum &i_T)
{
	memset(a, 0, sizeof(a));
	for (int i = str; i <= end; i++)
		a[i] = i_T.a[i];
	len = end - str + 1;
	while (a[len - 1] == 0 && len > 1)
		len--;
	cout << (*this) << ' ' << len << endl;
}
//int->BigNum
BigNum::BigNum(const int i_b)
{
	int c, d = i_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;
}
//char->BigNum
BigNum::BigNum(const char *i_s)
{
	int t, k, index, L;
	memset(a, 0, sizeof(a));
	L = strlen(i_s);
	len = L / DLEN;
	if (L%DLEN)
		len++;
	index = 0;
	for (int 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 + i_s[j] - '0';
		a[index++] = t;
	}
}
//copy
BigNum::BigNum(const BigNum &i_T) :len(i_T.len)
{
	memset(a, 0, sizeof(a));
	for (int i = 0; i < len; i++)
		a[i] = i_T.a[i];
}
//BigNum=BigNum
BigNum&BigNum::operator=(const BigNum&i_n)
{
	len = i_n.len;
	memset(a, 0, sizeof(a));
	for (int i = 0; i < len; i++)
		a[i] = i_n.a[i];
	return *this;
}
//cin>> BigNum
istream& operator >>(istream &in, BigNum &i_b)
{
	char ch[MAXSIZE * DLEN];
	in >> ch;
	int L = strlen(ch), count = 0, sum = 0;
	for (int i = L - 1; i >= 0;) {
		sum = 0;
		int t = 1;
		for (int j = 0; j < DLEN && i >= 0; j++, i--, t *= 10)
			sum += (ch[i] - '0')*t;
		i_b.a[count] = sum;
		count++;
	}
	i_b.len = count++;
	return in;
}
//cout<<BigNum
ostream& operator <<(ostream& out, BigNum& i_b)
{
	cout << i_b.a[i_b.len - 1];
	for (int i = i_b.len - 2; i >= 0; i--)
		printf("%04d", i_b.a[i]);
	return out;
}

BigNum BigNum::operator/(const BigNum &i_T)const
{
	BigNum t(*this), p(0);
	if (i_T > t)
		return p;
	while (t > i_T) {
		t = t - i_T;
		p = p + 1;
	}
	return p;
}

BigNum BigNum::operator/(const int &i_b)const
{
	BigNum ret;
	int down = 0;
	for (int i = len - 1; i >= 0; i--) {
		ret.a[i] = (a[i] + down * (MAXN + 1)) / i_b;
		down = a[i] + down * (MAXN + 1) - ret.a[i] * i_b;
	}
	ret.len = len;
	while (ret.a[ret.len - 1] == 0 && ret.len > 1)
		ret.len--;
	return ret;
}

long long BigNum::operator%(const long long &i_b)const
{
	long long d = 0;
	for (int i = len - 1; i >= 0; i--)
		d = ((d*MAXN + 1) % i_b + a[i] * 1LL) % i_b;
	return d;
}

BigNum BigNum::operator^(const int &n)const
{
	int i;
	BigNum t, ret(1);
	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 &i_T)const
{
	int ln;
	if (len > i_T.len)
		return true;
	else if (len < i_T.len)
		return false;
	else {
		ln = len - 1;
		while (a[ln] == i_T.a[ln] && ln > 0)
			ln--;
		return (ln >= 0 && a[ln] > i_T.a[ln]);
	}
}

bool BigNum::operator>(const int &i_T)const
{
	BigNum b(i_T);
	return *this > b;
}

void BigNum::print()
{
	printf("%d", a[len - 1]);
	for (int i = len - 2; i >= 0; i--)
		printf("%04d", a[i]);
	printf("\n");
}

BigNum BigNum::operator*(const BigNum &i_T)const
{
	BigNum ret;
	int up, i=0, j=0, temp, temp1;
	for (i = 0; i < len; i++) {
		up = 0;
		for (j = 0; j < i_T.len; j++) {
			temp = a[i] * 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 BigNum &i_T)const	//BigNum+BigNum
{
	BigNum t(*this);
	int big;
	big = i_T.len > len ? i_T.len : len;
	for (int i = 0; i < big; i++) {
		t.a[i] += i_T.a[i];
		if (t.a[i] > MAXN) {
			t.a[i + 1]++;
			t.a[i] -= MAXN + 1;
		}
	}
	t.len = (t.a[big] != 0) ? big + 1 : big;
	return t;
}

BigNum BigNum::operator-(const BigNum &i_T)const //num - num
{
	int big, j;
	bool flag;
	BigNum t1, t2;
	if (*this > i_T) {
		t1 = *this;
		t2 = i_T;
		flag = 0;
	}
	else {
		t1 = i_T;
		t2 = *this;
		flag = 1;
	}
	big = t1.len;
	for (int 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;
}

划分树

typedef unsigned long long ull;
const int MAXN = 1e5 + 10;
int tree[20][MAXN], sorted[MAXN], toleft[20][MAXN];
void built(int l, int r, int dep)
{
	if (l == r)
		return;
	int mid = (l + r) >> 1, same = mid - l + 1;
	for (int i = l; i <= r; i++)
		if (tree[dep][i] < sorted[mid])
			same--;
	int lpos = l, rpos = mid + 1;
	for (int i = l; i <= r; i++) {
		if (tree[dep][i] < sorted[mid])
			tree[dep + 1][lpos++] = tree[dep][i];
		else if (tree[dep][i] == sorted[mid] && same > 0) {
			tree[dep + 1][lpos++] = tree[dep][i];
			same--;
		}
		else
			tree[dep + 1][rpos++] = tree[dep][i];
		toleft[dep][i] = toleft[dep][l - 1] + lpos - l;
	}
	built(l, mid, dep + 1);
	built(mid + 1, r, dep + 1);
}
int query(int L, int R, int l, int r, int dep, int k)
{
	if (l == r)
		return tree[dep][l];
	int mid = (L + R) >> 1;
	int cnt = toleft[dep][r] - toleft[dep][l - 1];
	if (cnt >= k) {
		int newl = L + toleft[dep][l - 1] - toleft[dep][L - 1];
		int newr = newl + cnt - 1;
		return query(L, mid, newl, newr, dep + 1, k);
	}
	else {
		int newr = r + toleft[dep][R] - toleft[dep][r];
		int newl = newr - (r - l - cnt);
		return query(mid + 1, R, newl, newr, dep + 1, k - cnt);
	}
}
int main()
{
	int n, m;
	while (cin >> n >> m) {
		memset(tree, 0, sizeof(tree));
		for (int i = 1; i <= n; i++) {
			cin >> tree[0][i];
			sorted[i] = tree[0][i];
		}
		sort(sorted + 1, sorted + n + 1);
		built(1, n, 0);
		int s, t, k;
		while (m--) {
			cin >> s >> t >> k;
			cout << query(1, n, s, t, 0, k) << endl;
		}
	}
}

珂朵莉树

typedef long long ll;
typedef set<struct node>::iterator IT;
struct node {
    int l, r;
    mutable ll v;
    node(int _l, int _r = -1, ll _v = 0)
        : l(_l)
        , r(_r)
        , v(_v)
    {
    }
    bool operator<(const node& i_T) const
    {
        return l < i_T.l;
    }
};
set<node> s;
inline IT split(int pos)
{
    IT it = s.lower_bound(node(pos));
    if (it != s.end() && it->l == pos)
        return it;
    it--;
    node _p = *it;
    s.erase(it);
    s.insert(node(_p.l, pos - 1, _p.v));
    return s.insert(node(pos, _p.r, _p.v)).first;
}
inline void update(int l, int r, int val)
{
    IT itr = split(r + 1), itl = split(l);
    s.erase(itl, itr);
    s.insert(node(l, r, val));
}
/**
 * 其他操作如下类似
 * */
inline void add(int l, int r, int val)
{
    IT itr = split(r + 1), itl = split(l);
    for (; itl != itr; itl++)
        itl->v += val;
}

配对堆(可并堆

应该是monkey king那个题目

/**
 * 输入n和t
 * 代表n个只有一个数的堆,以及t个操作
 * opt=1时,将x和y所在的堆合并,若x或y被删除则跳过
 * opt=2时,将x所在堆的堆顶.按照从小到大,相等时按照编号从小到大弹出.
 * 弹出并删除该数
 * */
struct num {
    int val;
    int i;
    bool operator>(num a)
    {
        return (val == a.val ? i > a.i : val > a.val);
    }
};
typedef struct node* nd;
struct node {
    nd next;
    nd son;
    int size;
    num val;
    node()
    {
        val = num();
        son = next = NULL;
    }
};
struct vec {
    int fa;
    nd root;
} a[MAXN];
void add(nd p, nd ip)
{
    ip->next = p->son;
    p->son = ip;
}
nd merge(nd p, nd ip)
{
    if (p == NULL)
        return ip;
    if (ip == NULL)
        return p;
    if (p->val > ip->val)
        swap(p, ip);
    add(p, ip);
    p->size += ip->size;
    return p;
}
nd push(nd p, num val)
{
    if (p == NULL) {
        p = new (node);
        p->val = val;
        p->size++;
    } else {
        nd ip = new (node);
        ip->val = val;
        p = merge(p, ip);
    }
    return p;
}
num top(nd p)
{
    if (p == NULL) {
        cout << -1 << endl;
        exit(10);
    }
    return p->val;
}
nd pop(nd p)
{
    if (p->son == NULL) {
        delete (p);
        return NULL;
    }
    queue<nd> q;
    for (nd x = p->son; x != NULL; x = x->next)
        q.push(x);
    delete (p);
    while (q.size() > 1) {
        nd x = q.front();
        q.pop();
        nd y = q.front();
        q.pop();
        q.push(merge(x, y));
    }
    return q.front();
}
void del(nd p)
{
    stack<nd> st;
    if (p == NULL)
        return;
    for (nd x = p->son; x != NULL; x = x->next) {
        st.push(x);
        del(x);
    }
    while (!st.empty()) {
        delete (st.top());
        st.pop();
    }
}
int ffa(int x)
{
    return a[x].fa = (x == a[x].fa ? x : ffa(a[x].fa));
}
bool bk[MAXN];
int main()
{
    int n, t;
    cin >> n >> t;
    for (int i = 1; i <= n; i++) {
        int val;
        cin >> val;
        a[i].fa = i;
        a[i].root = push(a[i].root, num{ val, i });
    }
    while (t--) {
        int opt, x, y;
        cin >> opt >> x;
        if (opt == 1) {
            cin >> y;
            int fx = ffa(x), fy = ffa(y);
            if (!bk[x] && !bk[y] && fx != fy) {
                a[fy].fa = fx;
                a[fx].root = merge(a[fx].root, a[fy].root);
                a[fy].root = NULL;
            }
        } else {
            int fx = ffa(x);
            if (bk[x])
                cout << -1 << endl;
            else {
                num val = top(a[fx].root);
                cout << val.val << endl;
                a[fx].root = pop(a[fx].root);
                bk[val.i] = 1;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        int fi = ffa(i);
        if (a[fi].root != NULL) {
            del(a[fi].root);
            delete (a[fi].root);
            a[fi].root = NULL;
        }
    }
    return 0;
}

权值线段树

const int MAXN = 1e5 + 10;

/**
 * 求第k大值
 **/
struct vec {
    int v;
    int l, r;
} tree[MAXN << 1];
int root;

void built(int p, int l, int r) //建树,初始化
{
    tree[p].l = l, tree[p].r = r;
    if (l == r) {
        tree[p].v = 0;
        return;
    }
    int mid = (l + r) >> 1;
    built(p << 1, l, mid);
    built((p << 1) + 1, mid + 1, r);
}
void update(int p, int l, int r, int x) //插入一个数
{
    if (l == r) {
        tree[p].v++;
        return;
    }
    int mid = (l + r) >> 1;
    x <= mid ? update((p << 1), l, mid, x) : update((p << 1) + 1, mid + 1, r, x);
    tree[p].v = tree[(p << 1)].v + tree[(p << 1) + 1].v;
}
int query(int p, int l, int r, int x) //求一个数出现的次数
{
    if (l == r && l == x)
        return tree[p].v;
    int mid = (l + r) >> 1;
    return (x <= mid ? query((p << 1), l, mid, x) : query((p << 1) + 1, mid + 1, r, x));
}
int sum(int p, int l, int r) //求[l,r]区间内数出现的次数
{
    int L = tree[p].l, R = tree[p].r;
    if (l == L && r == R)
        return tree[p].v;
    int mid = (L + R) >> 1;
    if (r <= mid)
        return sum((p << 1), l, r);
    else if (l > mid)
        return sum((p << 1) + 1, l, r);
    return sum((p << 1), l, mid) + sum((p << 1) + 1, mid + 1, r);
}
int k_th(int p, int l, int r, int x) //查询所有数的第k大
{
    if (l == r)
        return l;
    int mid = (l + r) >> 1, num = tree[p << 1].v;
    return (x <= num ? k_th((p << 1), l, mid, x) : k_th((p << 1) + 1, mid + 1, r, x - num));
}
int a[MAXN];
int main()
{
    int n, m;
    cin >> n >> m;
    root = 1;
    int maxx = 0;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> a[i];
        maxx = max(maxx, a[i]);
    }
    built(root, 0, maxx);
    for (int i = 0; i < n; i++)
        update(root, 0, maxx, a[i]);
    for (int i = 1; i <= n; i++)
        cout << k_th(root, 0, maxx, i) << endl;
}

树状数组

typedef long long ll;
const int MAXN = 1e6 + 10;
int tree[MAXN], n;
inline int lowbit(int x) //核心操作,取x这个数的二进制最后一位1
{
    return -x & x;
}
inline void update(int x, int k) //单点修改
{
    for (; x <= n; x += lowbit(x))
        tree[x] += k;
}
inline int query(int x) //求x的前缀和
{
    int sum(0);
    for (; x > 0; x -= lowbit(x))
        sum += tree[x];
    return sum;
}

线段树

#define l(p) (p << 1)
#define r(p) (p << 1 | 1)

struct vec {
    ll d;
    ll lazy;
    ll L, R;
} tree[MAXN << 2];
void built(int p, ll l, ll r) {
    tree[p].L = l, tree[p].R = r;
    tree[p].lazy = 0;
    if (l == r)
        tree[p].d = 0;
    else {
        int mid = (l + r) >> 1;
        built(l(p), l, mid);
        built(r(p), mid + 1, r);
        tree[p].d = tree[l(p)].d + tree[r(p)].d;
    }
}
void pushdown(int p) {
    if (l(p) && r(p)) {
        tree[l(p)].lazy += tree[p].lazy;
        tree[r(p)].lazy += tree[p].lazy;
        tree[l(p)].d += tree[p].lazy * (tree[l(p)].R - tree[l(p)].L + 1);
        tree[r(p)].d += tree[p].lazy * (tree[r(p)].R - tree[r(p)].L + 1);
    }
    tree[p].lazy = 0;
}
ll query(int p, ll l, ll r) {
    pushdown(p);
    ll L = tree[p].L, R = tree[p].R;
    if (L == l && R == r)
        return tree[p].d;
    ll mid = (L + R) >> 1;
    if (l > mid)
        return query(r(p), l, r);
    else if (r <= mid)
        return query(l(p), l, r);
    return query(l(p), l, mid) + query(r(p), mid + 1, r);
}
void up(int p) {
    tree[p].d = tree[l(p)].d + tree[r(p)].d;
}
void update(int p, ll l, ll r, ll k) {
    pushdown(p);
    ll L = tree[p].L, R = tree[p].R;
    if (L == l && r == R) {
        tree[p].d += k * (tree[p].R - tree[p].L + 1);
        tree[p].lazy += k;
        return;
    }
    ll mid = (L + R) >> 1;
    if (l > mid)
        update(r(p), l, r, k);
    else if (r <= mid)
        update(l(p), l, r, k);
    else
        update(l(p), l, mid, k), update(r(p), mid + 1, r, k);
    up(p);
}
int main() {
    int root = 1;
    built(root, 0, 2e6);
    ll a, b, c, d;
    cin >> a >> b >> c >> d;
    for (int i = 0; i <= d; i++) 
        update(root, max(0LL, i - c), i, 1);
    ll sum = 0;
    for (int i = 0; i <= a; i++) 
        sum += query(root, i, i + b);
    cout << sum << endl;
    return 0;
}

骚操作

#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
const long long INF = LLONG_MAX;
const long long ENF = LLONG_MIN;
const double DINT = DBL_MAX;
const double DENF = DBL_MIN;
const int inf = __INT_MAX__;
const int enf = INT_MIN;

主席树

const int MAXN = 2e5 + 10;
#define ls(x) tree[x].lson
#define rs(x) tree[x].rson
/**
 * 求l,r区间内的第k小值
 * */
struct vec {
    int v;
    int lson, rson;
} tree[MAXN << 5];
int root[MAXN], tot;
int a[MAXN], b[MAXN];
void built(int& p, int l, int r) //建树,初始化
{
    p = ++tot;
    tree[p].v = 0;
    if (l >= r)
        return;
    int mid = (l + r) >> 1;
    built(ls(p), l, mid);
    built(rs(p), mid + 1, r);
}
void update(int& p, int pre, int l, int r, int pos)
{
    p = ++tot;
    tree[p].v = tree[pre].v + 1;
    ls(p) = ls(pre);
    rs(p) = rs(pre);
    if (l >= r)
        return;
    int mid = (l + r) >> 1;
    pos <= mid ? update(ls(p), ls(pre), l, mid, pos) : update(rs(p), rs(pre), mid + 1, r, pos);
}
int query(int p, int pre, int l, int r, int pos)
{
    if (l >= r)
        return l;
    int mid = (l + r) >> 1, num = tree[ls(p)].v - tree[ls(pre)].v;
    return (pos <= num ? query(ls(p), ls(pre), l, mid, pos) : query(rs(p), rs(pre), mid + 1, r, pos - num));
}
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    int cnt = unique(b + 1, b + n + 1) - b - 1;
    built(root[0], 1, cnt);
    for (int i = 1; i <= n; i++) {
        int pos = lower_bound(b + 1, b + cnt + 1, a[i]) - b;
        update(root[i], root[i - 1], 1, cnt, pos);
    }
    while (m--) {
        int l, r, k;
        cin >> l >> r >> k;
        cout << b[query(root[r], root[l - 1], 1, cnt, k)] << endl;
    }
}

最大子段和线段树

#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
struct node {
    int d;
    int pre_sum, post_sum, sum;
    node operator+(const node p) const
    {
        node ip;
        ip.d = d + p.d;
        ip.sum = max(max(sum, p.sum), post_sum + p.pre_sum);
        ip.pre_sum = max(pre_sum, d + p.pre_sum);
        ip.post_sum = max(p.post_sum, post_sum + p.d);
        return ip;
    }
} tree[MAXN << 2];
int root = 1, rub;
int a[MAXN];
void up(int p)
{
    tree[p] = tree[ls(p)] + tree[rs(p)];
}
void built(int p, int l, int r)
{
    if (l == r)
        tree[p].d = tree[p].post_sum = tree[p].pre_sum = tree[p].sum = a[l];
    else {
        int mid = (l + r) >> 1;
        built(ls(p), l, mid);
        built(rs(p), mid + 1, r);
        up(p);
    }
}
void update(int p, int l, int r, int pos, int k)
{
    if (l == r && l == pos)
        tree[p].d = tree[p].post_sum = tree[p].pre_sum = tree[p].sum = k;
    else {
        int mid = (l + r) >> 1;
        pos <= mid ? update(ls(p), l, mid, pos, k) : update(rs(p), mid + 1, r, pos, k);
        up(p);
    }
}
node query(int p, int L, int R, int l, int r)
{
    if (l == L && R == r)
        return tree[p];
    int mid = (l + r) >> 1;
    if (R <= mid)
        return query(ls(p), L, R, l, mid);
    else if (L > mid)
        return query(rs(p), L, R, mid + 1, r);
    else
        return query(ls(p), L, mid, l, mid) + query(rs(p), mid + 1, R, mid + 1, r);
}
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    built(root, 1, n);
    int q;
    cin >> q;
    for (int i = 1; i <= q; i++) {
        int l, r;
        cin >> l >> r;
        cout << query(root, l, r, 1, n).sum << endl;
    }
    return 0;
}

K-D树

#define lson(p) tree[p].lson
#define rson(p) tree[p].rson
/**
 * 求矩形区域内点的个数
 * */
const int MAXN = 2e5 + 10;
struct point {
    int x[2], w;
    bool operator<(const point a);
} m[MAXN];
struct node {
    point p;
    int lson, rson;
    int sz;
    int mi[2], mx[2], sum;
} tree[MAXN << 1];
int top, cur, rub[MAXN], WD, root;
bool point::operator<(const point a)
{
    return x[WD] < a.x[WD];
}
void up(int p)
{
    for (int i = 0; i <= 1; i++) {
        tree[p].mi[i] = tree[p].mx[i] = tree[p].p.x[i];
        if (lson(p))
            tree[p].mi[i] = min(tree[p].mi[i], tree[lson(p)].mi[i]);
        if (rson(p))
            tree[p].mi[i] = min(tree[p].mi[i], tree[rson(p)].mi[i]);
        if (lson(p))
            tree[p].mx[i] = max(tree[p].mx[i], tree[lson(p)].mx[i]);
        if (rson(p))
            tree[p].mx[i] = max(tree[p].mx[i], tree[rson(p)].mx[i]);
    }
    tree[p].sum = tree[lson(p)].sum + tree[rson(p)].sum + tree[p].p.w;
    tree[p].sz = 1 + tree[lson(p)].sz + tree[rson(p)].sz;
}
int newnode()
{
    if (top)
        return rub[top--];
    return ++cur;
}
void pia(int k, int num)
{
    if (lson(k))
        pia(lson(k), num);
    m[tree[lson(k)].sz + num + 1] = tree[k].p;
    rub[++top] = k;
    if (rson(k))
        pia(rson(k), num + tree[lson(k)].sz + 1);
}
int rebuilt(int l, int r, int d)
{
    if (l > r)
        return 0;
    int mid = (l + r) >> 1, k = newnode();
    WD = d;
    nth_element(m + l, m + mid, m + r + 1);
    tree[k].p = m[mid];
    lson(k) = rebuilt(l, mid - 1, d ^ 1);
    rson(k) = rebuilt(mid + 1, r, d ^ 1);
    up(k);
    return k;
}
void check(int& k, int d)
{
    if (tree[k].sz * 0.75 < tree[lson(k)].sz || tree[k].sz * 0.75 < tree[rson(k)].sz)
        pia(k, 0), k = rebuilt(1, tree[k].sz, d);
}
void insert(int& p, point k, int d)
{
    if (p == 0) {
        p = newnode();
        tree[p].p = k;
        lson(p) = rson(p) = 0;
        up(p);
        return;
    }
    if (tree[p].p.x[d] < k.x[d])
        insert(rson(p), k, d ^ 1);
    else
        insert(lson(p), k, d ^ 1);
    up(p), check(p, d);
}
bool in(int x1[], int x2[], int X1[], int X2[])
{
    return (X1[0] >= x1[0] && X2[0] <= x2[0] && X1[1] >= x1[1] && X2[1] <= x2[1]);
}
bool out(int x1[], int x2[], int X1[], int X2[])
{
    return (x1[0] > X2[0] || x2[0] < X1[0] || x1[1] > X2[1] || x2[1] < X1[1]);
}
int query(int k, int x1[], int x2[])
{
    if (k == 0)
        return 0;
    int ans = 0;
    if (in(x1, x2, tree[k].mi, tree[k].mx))
        return tree[k].sum;
    if (out(x1, x2, tree[k].mi, tree[k].mx))
        return 0;
    if (in(x1, x2, tree[k].p.x, tree[k].p.x))
        ans += tree[k].p.w;
    return query(lson(k), x1, x2) + query(rson(k), x1, x2) + ans;
}
point a[MAXN];
int built(int l, int r, int d)
{
    if (l > r)
        return 0;
    int mid = (l + r) >> 1, k = newnode();
    WD = d;
    nth_element(a + l, a + mid, a + r + 1), tree[k].p = a[mid];
    tree[k].lson = built(l, mid - 1, d ^ 1), tree[k].rson = built(mid + 1, r, d ^ 1);
    up(k);
    return k;
}
int main()
{
    int ans = 0;
    int k, q;
    cin >> k >> q;
    for (int i = 1; i <= k; i++) {
        cin >> a[i].x[0] >> a[i].x[1];
        a[i].w = 1;
    }
    root = built(1, k, 0);
    for (int i = 1; i <= q; i++) {
        int x1[2], x2[2];
        cin >> x1[0] >> x1[1] >> x2[0] >> x2[1];
        ans = query(root, x1, x2);
        printf("%d\n", ans);
    }
    return 0;
}

LCT

/**
 * + u v c:将u到v的路径上的点的权值都加上自然数c;
 * 
 * - u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
 * 
 * \* u v c:将u到v的路径上的点的权值都乘上自然数c;
 * 
 * / u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。
 * */
const int mod = 51061;
const int N = 100009;
typedef long long ll;
int n, st[N];
class LCT{
public:
    struct vec {
        int son[2], f;
        bool tag;
        ll val, sum, sz, mul, add;
    } p[N];
    inline bool isroot(int x)
    { //好像Daaddo都写的是isroot
        return p[p[x].f].son[0] == x || p[p[x].f].son[1] == x;
    }
    inline void pushup(int x)
    {
        p[x].sum = (p[p[x].son[0]].sum + p[p[x].son[1]].sum + p[x].val) % mod;
        p[x].sz = p[p[x].son[0]].sz + p[p[x].son[1]].sz + 1;
    }
    inline void pushr(int x)
    { //翻转
        swap(p[x].son[0], p[x].son[1]);
        p[x].tag ^= 1;
    }
    inline void pushmul(int x, ll c)
    { //乘
        p[x].sum = (p[x].sum * c) % mod;
        p[x].val = p[x].val * c % mod;
        p[x].mul = p[x].mul * c % mod;
        p[x].add = p[x].add * c % mod;
    }
    inline void pushadd(int x, ll c)
    { //加
        p[x].sum = (p[x].sum + c * p[x].sz) % mod;
        p[x].val = (p[x].val + c) % mod;
        p[x].add = (p[x].add + c) % mod;
    }
    inline void pushdown(int x)
    {
        if (p[x].mul != 1)
            pushmul(p[x].son[0], p[x].mul), pushmul(p[x].son[1], p[x].mul), p[x].mul = 1;
        if (p[x].add)
            pushadd(p[x].son[0], p[x].add), pushadd(p[x].son[1], p[x].add), p[x].add = 0;
        if (p[x].tag) {
            if (p[x].son[0])
                pushr(p[x].son[0]);
            if (p[x].son[1])
                pushr(p[x].son[1]);
            p[x].tag = 0;
        }
    }
    inline void rotate(int x)
    {
        int y = p[x].f, z = p[y].f, k = p[y].son[1] == x, w = p[x].son[!k];
        if (isroot(y))
            p[z].son[p[z].son[1] == y] = x;
        p[x].son[!k] = y;
        p[y].son[k] = w;
        if (w)
            p[w].f = y;
        p[y].f = x;
        p[x].f = z;
        pushup(y);
    }
    inline void splay(int x)
    {
        int y = x, z = 0;
        st[++z] = y;
        while (isroot(y))
            st[++z] = y = p[y].f;
        while (z)
            pushdown(st[z--]);
        while (isroot(x)) {
            y = p[x].f;
            z = p[y].f;
            if (isroot(y))
                rotate((p[y].son[0] == x) ^ (p[z].son[0] == y) ? x : y);
            rotate(x);
        }
        pushup(x);
    }
    inline void access(int x)
    {
        for (int y = 0; x; x = p[y = x].f)
            splay(x), p[x].son[1] = y, pushup(x);
    }
    inline void makeroot(int x)
    {
        access(x);
        splay(x);
        pushr(x);
    }
    inline void split(int x, int y)
    {
        makeroot(x);
        access(y);
        splay(y);
    }
    inline void link(int x, int y)
    {
        makeroot(x);
        p[x].f = y;
    }
    inline void cut(int x, int y)
    {
        split(x, y);
        p[x].f = p[y].son[0] = 0;
    }
} root;
int main()
{
    int q, i, a, b, k;
    cin >> n >> q;
    for (i = 1; i <= n; ++i)
        root.p[i].val = root.p[i].sz = root.p[i].mul = 1; //注意乘法标记的初值为1
    for (i = 1; i < n; ++i) {
        cin >> a >> b;
        root.link(a, b);
    }
    while (q--) {
        char ch;
        cin >> ch;
        switch (ch) {
        case '+':
            cin >> a >> b >> k;
            root.split(a, b);
            root.pushadd(b, k);
            break;
        case '-':
            cin >> a >> b;
            root.cut(a, b);
            cin >> a >> b;
            root.link(a, b);
            break;
        case '*':
            cin >> a >> b >> k;
            root.split(a, b);
            root.pushmul(b, k);
            break;
        case '/':
            cin >> a >> b;
            root.split(a, b);
            cout << root.p[b].sum << endl;
        }
    }
    return 0;
}

LCT求LCA

/**
 * 动态LCA
 * 
 * 先将树根makeroot
 * 
 * 每次求x和y的公共祖先时
 * 
 * 先access(x),将x和s之间建一个实链,使他们在一个splay里.
 * 
 * 所以 y 到 LCA 一定是一条虚边,故在 access(y) 的时候每次记录跳过的虚边是跳到了谁那里
 * 
 * 然后将最后一次跑虚边的点(父亲)返回
 * */
const int mod = 51061;
const int N = 500009;
typedef long long ll;
int n, st[N];
class LCT {
public:
    struct vec {
        int son[2], f;
        bool tag;
        ll sz;
        vec()
        {
            sz = 1;
        }
    } p[N];
    inline bool isroot(int x)
    { //好像Daaddo都写的是isroot
        return p[p[x].f].son[0] == x || p[p[x].f].son[1] == x;
    }
    inline void pushup(int x)
    {
        p[x].sz = p[p[x].son[0]].sz + p[p[x].son[1]].sz + 1;
    }
    inline void pushr(int x)
    { //翻转
        swap(p[x].son[0], p[x].son[1]);
        p[x].tag ^= 1;
    }
    inline void pushdown(int x)
    {
        if (p[x].tag) {
            if (p[x].son[0])
                pushr(p[x].son[0]);
            if (p[x].son[1])
                pushr(p[x].son[1]);
            p[x].tag = 0;
        }
    }
    inline void rotate(int x)
    {
        int y = p[x].f, z = p[y].f, k = p[y].son[1] == x, w = p[x].son[!k];
        if (isroot(y))
            p[z].son[p[z].son[1] == y] = x;
        p[x].son[!k] = y;
        p[y].son[k] = w;
        if (w)
            p[w].f = y;
        p[y].f = x;
        p[x].f = z;
        pushup(y);
    }
    inline void splay(int x)
    {
        int y = x, z = 0;
        st[++z] = y;
        while (isroot(y))
            st[++z] = y = p[y].f;
        while (z)
            pushdown(st[z--]);
        while (isroot(x)) {
            y = p[x].f;
            z = p[y].f;
            if (isroot(y))
                rotate((p[y].son[0] == x) ^ (p[z].son[0] == y) ? x : y);
            rotate(x);
        }
        pushup(x);
    }
    inline void access(int x)
    {
        for (int y = 0; x; x = p[y = x].f)
            splay(x), p[x].son[1] = y, pushup(x);
    }
    inline void makeroot(int x)
    {
        access(x);
        splay(x);
        pushr(x);
    }
    inline void split(int x, int y)
    {
        makeroot(x);
        access(y);
        splay(y);
    }
    inline void link(int x, int y)
    {
        makeroot(x);
        p[x].f = y;
    }
    inline void cut(int x, int y)
    {
        split(x, y);
        p[x].f = p[y].son[0] = 0;
    }
    inline int LCA(int u, int v)
    {
        access(u);
        int ans = v;
        for (int i = 0; v; ans = i = v, v = p[i].f) {
            splay(v), p[v].son[1] = i;
        }
        return ans;
    }
} root;
int main()
{
    int n, m, s;
    cin >> n >> m >> s;
    int u, v;
    for (int i = 1; i < n; i++) {
        cin >> u >> v;
        root.link(u, v);
    }
    root.makeroot(s);
    while (m--) {
        cin >> u >> v;
        printf("%d\n", root.LCA(u, v));
    }
    return 0;
}

SPLAY

typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 1e5 + 10;
const int mod = 10007;
struct vec {
	int father;
	int son[2];
	int key;
	int cnt;
	int size;
	void built(int x) {
		size = cnt = 1;
		key = x;
		father = son[0] = son[1] = 0;
	}
	void clear() {
		father = son[0] = son[1] = key = cnt = size = 0;
	}
	void insert(int x, int fa) {
		size =cnt = 1;
		son[0] = son[1] = 0;
		father = fa;
		key = x;
	}
};
vec p[MAXN];
int root,Size;
void pushup(int x) 
{
	if (x) {
		p[x].size = p[x].cnt;
		if (p[x].son[0])
			p[x].size += p[p[x].son[0]].size;
		if (p[x].son[1])
			p[x].size += p[p[x].son[1]].size;
	}
}
bool get(int x)
{
	return p[p[x].father].son[1] == x;
}
void rotate(int x)
{
	int fa = p[x].father,ffa=p[fa].father,k=get(x),son=p[x].son[k^1];
	p[fa].son[k] = son;
	p[p[fa].son[k]].father = fa;

	p[x].son[k ^ 1] = fa;
	p[fa].father = x;

	p[x].father = ffa;
	if (ffa)
		p[ffa].son[p[ffa].son[1] == fa] = x;

	pushup(fa), pushup(x);
}
void splay(int x)
{
	if(p[x].father==0){
		root=x;
		return;
	}
  	int fa=p[x].father,ffa=p[fa].father;
    if(ffa)
        (p[ffa].son[0]==fa)^(p[fa].son[0]==x)?rotate(x):rotate(fa);
    rotate(x);
    splay(x);
}
void insert(int x)
{
	if (root == 0) {
		Size++;
		root = Size;
		p[root].built(x);
		return;
	}
	int now = root,fa=0;
	while (1) {
		if (x == p[now].key) {
			p[now].cnt++;
			pushup(now), pushup(fa);
			splay(now);
			return;
		}
		fa = now; now = p[now].son[p[now].key < x];
		if (now == 0) {
			Size++;
			p[Size].insert(x, fa);
			p[fa].son[p[fa].key < x] = Size;
			pushup(fa);
			splay(Size);
			return;
		}
	}
}
/**
*查询x的排名 
*/
int rnk(int x)
{
	int now = root, ans = 0;
	while (1) {
		if (x < p[now].key)
			now = p[now].son[0];
		else {
			ans += p[p[now].son[0]].size;
			if (x == p[now].key) {
				splay(now);
				return ans + 1;
			}
			ans += p[now].cnt;
			now = p[now].son[1];
		}
	}
}
/**
*找到排名为x的点
*/
int kth(int x)
{
	int now = root;
	while (1)
	{
		if (p[now].son[0] && x <= p[p[now].son[0]].size)
			now = p[now].son[0];
		else
		{
			int temp = p[p[now].son[0]].size + p[now].cnt;
			if (x <= temp)
				return p[now].key;
			x -= temp; 
			now = p[now].son[1];
		}
	}
}
/**
*求前驱后继
*/
int pre()
{
	int now = p[root].son[0];
	while (p[now].son[1]) now = p[now].son[1];
	return now;
}
int next()
{
	int now = p[root].son[1];
	while (p[now].son[0]) now = p[now].son[0];
	return now;
}
/**
*删除
*/
void del(int x)
{
	rnk(x);
	if (p[root].cnt > 1) {
		p[root].cnt--;
		pushup(root);
		return;
	}
	if (!p[root].son[0] && !p[root].son[1]) {
		p[root].clear();
		root = 0;
		return;
	}
	if (!p[root].son[0]) {
		int oldroot = root;
		root = p[root].son[1];
		p[root].father = 0;
		p[oldroot].clear();
		return;
	}
	else if (!p[root].son[1]) {
		int oldroot = root;
		root = p[root].son[0];
		p[root].father = 0;
		p[oldroot].clear();
		return;
	}
	int oldroot = root, leftbig = pre();
	splay(leftbig);
	p[root].son[1] = p[oldroot].son[1];
	p[p[oldroot].son[1]].father = root;
	p[oldroot].clear();
	pushup(root);
}
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		int opt,x;
		cin >> opt>>x;
		switch (opt) {
		case 1:
			insert(x);
			break;
		case 2:
			del(x);
			break;
		case 3:
			cout<<rnk(x)<<endl;
			break;
		case 4:
			cout << kth(x) << endl;
			break;
		case 5:
			insert(x);
			cout << p[pre()].key << endl;
			del(x);
			break;
		case 6:
			insert(x);
			cout << p[next()].key<<endl;
			del(x);
			break;
		}
	}
	return 0;
}

Stl的一些重载

/**
 * unordered_map的结构体重载
 * */
struct Node {
    Node() {}
    Node(int _x, int _y):x(_x), y(_y) {}
    int x, y;
};
struct NodeHash {
    std::size_t operator () (const Node &t) const {
        return  t.x * 100 + t.y;
    }
};
unordered_set <Node, NodeHash> h_set;
unordered_map <Node, string, NodeHash> h_map;

字符串

后缀数组

const int MAXN = 1e5 + 10;
char s[MAXN];
int rk[MAXN], sa[MAXN], tax[MAXN], hg[MAXN], n, m;
int tp[MAXN];
//tp第二关键字数组
//rk第一关键字第i位的排名,sa排名第i位的位置
void rsort(int a[], int b[]) {    //a第一关键字数组,b第二关键字数组
    for (int i = 0; i <= m; i++) //桶清零
        tax[i] = 0;
    for (int i = 1; i <= n; i++) //在第一关键字相同的情况下,按照第二关键字从小到大放入
        tax[a[b[i]]]++;
    for (int i = 1; i <= m; i++) //计算排名
        tax[i] += tax[i - 1];
    for (int i = n; i >= 1; i--) //在第一关键字相同的情况下,按照第二关键字从大到小取出
        sa[tax[a[b[i]]]--] = b[i];
}
void suffix() {
    for (int i = 1; i <= n; i++) //字母大小为第一关键字,位置为第二关键字
        rk[i] = s[i], tp[i] = i;
    rsort(rk, tp);
    for (int l = 1, num = 0; num != n; l <<= 1) {
        num = 0;
        for (int i = n - l + 1; i <= n; i++) //在n-l+1后面的位置都无法找到l位后的后续,所以为0
            tp[++num] = i;                   //所以先将位置存入
        for (int i = 1; i <= n; i++)         //sa[i]=排名i的后缀位置,如果>l,那么它就可以和sa[i]-l位置的第一关键字匹配
            if (sa[i] > l)
                tp[++num] = sa[i] - l;
        //此刻tp数组内情况:[第二关键字为0的一组的起始位置......第二关键字按照从小到大的一组的起始位置]
        rsort(rk, tp);
        //此处分割,上述为k阶段的sa以及排序,下述为k<<1阶段的rk
        swap(rk, tp); //用tp存储上一轮的rk,来为下一轮的rk做准备
        rk[sa[num = 1]] = 1;
        for (int i = 2; i <= n; i++) //排名相近的第一关键字和第二关键字是否相等
            rk[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + l] == tp[sa[i - 1] + l]) ? num : ++num;
        m = num;
    }
    return;
}
void get_height() {
    for (int i = 1; i <= n; i++) //这句话其实可加可不加
        rk[sa[i]] = i;
    for (int i = 1, k = 0; i <= n; i++) {
        if (k)
            k--;
        int j = sa[rk[i] - 1];
        while (s[i + k] == s[j + k])
            k++;
        hg[rk[i]] = k;
    }
}
int main() {
    cin >> (s + 1);
    n = strlen(s + 1);
    m = 122;
    suffix();
    get_height();
}

没看懂的后缀数组dc3

const int MAXN = 2010;
#define F(x) ((x)/3+((x)%3==1?0:tb))        //计算原字符串 suffix(x)在新的字符串中的起始位置
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)  //计算新字符串 suffix(x)在原字符串中的位置
//F(x)与G(x)为互逆运算
int wa[MAXN*3], wb[MAXN*3],  wv[MAXN*3],  wss[MAXN*3];//计算SA的过程数组
int c0(int *r,int a,int b) //比较是否完全相同
{
    return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2];
}
int c12(int k,int *r,int a,int b) //比较后缀大小的函数
{
    if(k == 2)   return r[a]<r[b] || (r[a]==r[b] && c12(1,r,a+1,b+1));
    else return r[a]<r[b] || ( r[a] == r[b] && wv[a+1]<wv[b+1] );
}
void sort(int *r,int *a,int *b,int n,int m) //基数排序
{
    int i;
    for(i = 0; i < n; i++) wv[i] = r[a[i]];
    for(i = 0; i < m; i++) wss[i] = 0;
    for(i = 0; i < n; i++) wss[wv[i]]++;
    for(i = 1; i < m; i++) wss[i] += wss[i-1];
    for(i = n-1; i >= 0; i--) b[--wss[wv[i]]] = a[i];
}
/*
ta: 下标i,满足 i%3==0 的个数
tb: 下标i,满足 i%3==1 的个数
tbc:下标i,满足 i%3!=0 的个数
*/
void dc3(int *r,int *sa,int n,int m) 
{
    int i, j, *rn = r+n;
    int *san = sa+n, ta = 0, tb=(n+1)/3, tbc=0, p;
    //起始位置模 3不等于 0 的后缀进行排序。
    //用基数排序把 3 个字符“合并”成一个新的字符
    r[n] = r[n+1] = 0;
    for(i = 0; i < n; i++) if(i%3 != 0) wa[tbc++] = i;
    sort(r+2, wa, wb, tbc, m);
    sort(r+1, wb, wa, tbc, m);
    sort(r, wa, wb, tbc, m); //基数排序结束后,新的字符的排名保存在 wb 数组中。
    //求新的字符串时要判断两个字符组是否完全相同。
    p=1, rn[F(wb(0))]=0;
    for(i = 1; i < tbc; i++)
        rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
    //求san
    if(p < tbc) dc3(rn, san, tbc, p);
    else for(i = 0; i < tbc; i++) san[rn[i]] = i;
    //起始位置模 3 等于 0 的后缀进行排序。
    for(i = 0; i < tbc; i++)  if(san[i] < tb) wb[ta++] = san[i]*3;
    if(n%3 == 1) wb[ta++] = n - 1; //因为在 san 数组里并没有suffix(n),要特殊处理
    sort(r, wb, wa, ta, m);
    //合并所有排序结果
    for(i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i;
    i = 0, j = 0;
    for(p = 0; i < ta && j < tbc; p++)
        sa[p] = c12(wb[j]%3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
    for(; i < ta; p++)sa[p] = wa[i++];
    for(; j < tbc; p++)sa[p] = wb[j++];
} //str和sa也要三倍
void Get_Height(int str[],int sa[],int Rank[],int height[],int n)
{
    int i,j,k = 0;
    for(i = 0; i <= n; i++) Rank[sa[i]] = i;
    for(i = 0; i < n; i++)
    {
        if(k) k--;
        j = sa[Rank[i]-1];
        while(str[i+k] == str[j+k]) k++;
        height[Rank[i]] = k;
    }
}
void solve(int str[],int sa[],int Rank[],int height[],int n,int m)
{
    for(int i = n; i < n*3; i++) str[i] = 0;
    dc3(str, sa, n+1, m);
    Get_Height(str, sa, Rank, height, n);
}

马拉车

char s[MAXN], s_new[MAXN];
int p[MAXN], a[27], sum[MAXN];
int get_s(int len) {
    s_new[0] = '$', s_new[1] = '#';
    int j = 2;
    for (int i = 1; i <= len; i++) {
        s_new[j++] = s[i];
        s_new[j++] = '#';
    }
    s_new[j] = '\0';
    return j;
}
void get_p(int len) {
    int id = 0, mx = 0;
    for (int i = 1; i <= len; i++) {
        p[i] = i < mx ? min(p[2 * id - i], mx - i) : 1;
        while (s_new[i - p[i]] == s_new[i + p[i]])
            p[i]++;
        if (mx < i + p[i])
            mx = i + p[i], id = i;
    }
}
int main() {
    while (~scanf("%s", (s + 1))) {
        int len = get_s(strlen(s + 1));
        get_p(len);
    }
}

字典树

const int MAXN = 1e5 + 10;
int tree[MAXN][30];
bool flag[MAXN];
int tot = 0;
void insert(char t[]) {
    int len = strlen(t), root = 0;
    for (int i = 0, x; i < len; i++) {
        x = t[i] - '0';
        if (!tree[root][x])
            tree[root][x] = ++tot;
        root = tree[root][x];
    }
    flag[root] = 1;
}
bool query(char t[]) {
    int len = strlen(t), root = 0;
    for (int i = 0, x; i < len - 1; i++) {
        x = t[i] - '0';
        root = tree[root][x];
        if (flag[root])
            return 0;
    }
    return flag[tree[root][t[len] - 'a']];
}

AC自动机

const int MAXN = 2e6 + 10;
int tree[MAXN][30], cnt[MAXN], fail[MAXN];
int tot;
void insert(char t[]) {
    int root = 0;
    for (int i = 0, x; t[i]; i++) {
        x = t[i] - 'a';
        if (!tree[root][x])
            tree[root][x] = ++tot;
        root = tree[root][x];
    }
    cnt[root]++;
}
void init() {
    for (int i = 0; i <= tot; i++) {
        fail[i] = cnt[i] = 0;
        for (int j = 0; j < 26; j++)
            tree[i][j] = 0;
    }
}
void build() {
    queue<int> q;
    for (int i = 0; i < 26; i++)
        if (tree[0][i])
            q.push(tree[0][i]);

    while (!q.empty()) {
        int now = q.front();
        q.pop();
        for (int i = 0; i < 26; i++)
            if (tree[now][i]) {
                fail[tree[now][i]] = tree[fail[now]][i]; //它爹的fail的儿子
                q.push(tree[now][i]);
            } else
                tree[now][i] = tree[fail[now]][i]; //路径压缩
    }
}
int query(char t[]) {
    int now = 0, ans = 0;
    for (int i = 0; t[i]; i++)
        for (int j = now = tree[now][t[i] - 'a']; j && ~cnt[j]; j = fail[j])
            ans += cnt[j], cnt[j] = -1;
    return ans;
}
char s[MAXN];
int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        scanf("%d", &n);
        init();
        tot = 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", s);
            insert(s);
        }
        build();
        scanf("%s", s);
        printf("%d\n", query(s));
    }
}

hash

ull p[MAXN], h1[MAXN], h2[MAXN];
char s1[MAXN], s2[MAXN];
ull key = 1313131;
void get_hash(char t[], int len, ull pi[]) {
    for (int i = 1; i <= len; i++)
        pi[i] = pi[i - 1] * key + t[i];
}
ull find_hash(int l, int r, ull pi[]) {
    return pi[r] - pi[l - 1] * p[r - l + 1];
}
void init() {
    p[1] = key;
    for (int i = 2; i <= 100000; i++)
        p[i] = p[i - 1] * key;
}

KMP

char t[1000100], s[1000100];
int len1, len2, n[1000100];
void KMP(char *s, char *t) {
    for (int i = 0, j = -1; i < len1; i++) {
        while (j != -1 && t[j + 1] != s[i])
            j = n[j];
        if (t[j + 1] == s[i])
            j++;
        if (j == len2 - 1) {
            cout << i - len2 + 2 << endl;
            j = n[j];
        }
    }
}
void getnext(char *t) {
    n[0] = -1;
    for (int i = 1, j = -1; i < len2; i++) {
        while (j != -1 && t[i] != t[j + 1])
            j = n[j];
        if (t[i] == t[j + 1])
            j++;
        n[i] = j;
    }
}
int main() {
    cin >> s >> t;
    len1 = strlen(s);
    len2 = strlen(t);
    getnext(t);
    KMP(s, t);
    for (int i = 0; i < len2; i++)
        cout << n[i] + 1 << ' ';
    return 0;
}

图论

克鲁斯卡尔

int mp[150][150], fa[150];
struct Edge {
    Edge(int _u = 0, int _v = 0, int _w = 0)
        : u(_u)
        , v(_v)
        , w(_w)
    {
    }
    int u, v, w;
    bool operator<(Edge a)
    {
        return w < a.w;
    }
} e[100000];
int cnt;
int find(int x)
{
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            cin >> mp[i][j];
            e[cnt++] = Edge(i, j, mp[i][j]);
        }
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    sort(e, e + cnt);
    int ans = 0, p = 0;
    for (int i = 0; i < cnt && p != n; i++) {
        int fu, fv;
        if ((fu = find(e[i].u)) != (fv = find(e[i].v))) {
            fa[fu] = fv;
            ans += e[i].w;
            p++;
        }
    }
    cout << ans << endl;
    return 0;
}

堆优化前向星迪杰斯特拉

const int inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;
struct node {
    int c, v;
    node(int _v = 0, int _c = 0)
        : v(_v)
        , c(_c)
    {
    }
    bool operator<(const node& i_T) const
    {
        return c > i_T.c;
    }
};
struct Edge {
    int v, cost, next;
    Edge(int _v = 0, int _cost = 0, int _next = 0)
        : v(_v)
        , cost(_cost)
        , next(_next)
    {
    }
} e[MAXN << 1];
int head[MAXN], cnt;
void add(int u, int v, int cost)
{
    cnt++;
    e[cnt] = Edge(v, cost, head[u]);
    head[u] = cnt;
}
bool vis[MAXN];
int dist[MAXN];
void dij(int n, int st)
{
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++)
        dist[i] = inf;
    priority_queue<node> que;
    while (que.size())
        que.pop();
    dist[st] = 0;
    que.push(node(st, 0));
    node tmp;
    while (!que.empty()) {
        tmp = que.top();
        que.pop();
        int u = tmp.v;
        if (vis[u])
            continue;
        vis[u] = 1;
        for (int i = head[u]; i != 0; i = e[i].next) {
            int v = e[i].v;
            int cost = e[i].cost;
            if (!vis[v] && dist[v] > dist[u] + cost) {
                dist[v] = dist[u] + cost;
                que.push(node(v, dist[v]));
            }
        }
    }
}
int main()
{
    int n, m, st, et;
    cin >> n >> m >> st >> et;
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
    }
    dij(n, st);
    cout << dist[et] << endl;
    return 0;
}

博弈

1、巴什博弈:

n%(m+1) != 0,先手肯定获胜

2、尼姆博弈

把每堆物品数全部异或起来,若值为0,则先手必败,否则先手必胜。

3、斐波那契博弈(k倍动态减法)

当且仅当n不是斐波那契数时,先手胜。

扩展:k倍动态减法

我们手动构建一个a数列,若n是该数列中的数时,先手必败,否则后手必败。即该数列是必败态。

构建队列模板

const int N = 10010;
int main()
{
	int n,k,a[N],b[N];
	cin >> n >> k;
	a[0] = b[0] = 1;
	int i = 0,j = 0;
	while(n > a[i])
	{
		i++;
		a[i] = b[i-1] + 1;
		while(a[j+1] * k < a[i])
			j++;
		if(a[j] * k < a[i])
			b[i] = b[j] + a[i];
		else
			b[i] = a[i];
	}
	if(n == a[i])
		cout << "lose" << endl;
	else
		cout << "win" << endl;

	return 0;
}

4、威佐夫博弈

2.结论: 我们规定两堆数量为a和b且a < b,若a和b的差值乘上1.618恰好是a的值,则次为必败态,先手必败。有时追求精度可记\(w=\left \lfloor \frac{\sqrt{5}+1}{2}\times{(b-a)} \right \rfloor\)\(w = a\),则先手必败,否则先手必胜。

int main()
{
	int a,b;
	cin >> a >> b;
	if(b < a)
		swap(a,b);
	double c = (double)(b-a);
	int w = (int)(((sqrt(5)+1) / 2) * (b-a));
	if(w == a)
		cout << "lose" << endl;
	else
		cout << "win" << endl;
	return 0;
}

树形博弈

Hackenbush游戏是通过移除一个有根图的某些边,直到没有与地板的相连的边,可以转变为nim博弈
Colon Principle:当树枝在一个顶点上时,用一个非树枝的杆的长度来替代,相当于他们的n异或之和。
void dfs(int pi) {
    v[pi] = 1;
    for(auto it:e[pi]) {
        if (!v[it.y]) {
            dfs(it.y);
            d[pi] ^= d[it.y] + 1;
        }
    }
}

SG函数

有向图游戏的某个局面必胜,当且仅当该局面对应节点的SG函数值大于0

有向图游戏的某个局面必败,当且仅当该局面对应节点的SG函数值等于0

//f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
//SG[]:0~n的SG函数值
//S[]:为x后继状态的集合
int f[N],SG[MAXN],S[MAXN];
void  getSG(int n){
    int i,j;
    memset(SG,0,sizeof(SG));
    //因为SG[0]始终等于0,所以i从1开始
    for(i = 1; i <= n; i++){
        //每一次都要将上一状态 的 后继集合 重置
        memset(S,0,sizeof(S));
        for(j = 0; f[j] <= i && j <= N; j++)
            S[SG[i-f[j]]] = 1;  //将后继状态的SG函数值进行标记
        for(j = 0;; j++) if(!S[j]){   //查询当前后继状态SG值中最小的非零值
            SG[i] = j;
            break;
        }
    }
}

数论

扩展欧几里得,求逆元

/**
 * 扩展欧几里得
 * 反正把a扔进去就能求它的逆元
 * */
ll ex_gcd(ll a, ll b, ll& x, ll& y)
{
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll d = ex_gcd(b, a % b, x, y);
    ll t = x;
    x = y, y = t - (a / b) * y;
    return d;
}
inline ll inv(ll a, ll b) //求逆元
{
    ll inv_a, y;
    ex_gcd(a, b, inv_a, y);
    return (inv_a % b + b) % b;
}

JAVA 大数开方

private static BigDecimal sqrt(BigDecimal x, int n) {
        BigDecimal ans = BigDecimal.ZERO;
        BigDecimal eps = BigDecimal.ONE;
        for (int i = 0; i < n; ++i) {
            while (ans.pow(2).compareTo(x) < 0) {
                ans = ans.add(eps);
            }
            ans = ans.subtract(eps);
            eps = eps.divide(BigDecimal.TEN);
        }
        return ans;
    }

快速幂

ll quick_pow(ll a, ll b, ll mod)
{
    ll sum = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1)
            sum = sum * a % mod;
    return sum;
}

矩阵快速幂

/**
 * 矩阵快速幂
 * 写个结构体,重载*运算符
 * n是次数
 * N是行和列
 * */
struct Matrix {
    long long a[N][N];
    Matrix()
    {
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                a[i][j] = 0;
    }
    Matrix operator*(Matrix& i_T)
    {
        Matrix t;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                t.a[i][j] = 0;
                for (int k = 0; k < N; k++)
                    t.a[i][j] = (t.a[i][j] + (a[i][k] * i_T.a[k][j])) % mod;
            }
        }
        return t;
    }
    Matrix quickpow(Matrix M, long long n)
    {
        Matrix t;
        //初始化为单位矩阵
        //初始化
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (i == j)
                    t.a[i][j] = 1;
                else
                    t.a[i][j] = 0;
            }
        }
        //快速幂(类似整数)
        while (n) {
            if (n & 1)
                t = t * M;
            n = n >> 1;
            M = M * M;
        }
        return t;
    }
};

素数筛

/**
 * 素数筛
 * */
//欧拉筛 nloglogn
void make_prime()
{
    prime[0] = prime[1] = 1;
    for (int i = 2; i <= MAXN; i++) {
        if (!prime[i])
            Prime[num++] = i;
        for (int j = 0; j < num && i * Prime[j] < MAXN; j++) {
            prime[i * Prime[j]] = 1;
            if (i % Prime[j])
                break;
        }
    }
    return;
}

Miller_rabin,判断一个数是否为素数

//Miller_rabin,判断一个数是否为素数
ll Mult_Mod(ll a, ll b, ll m) //res=(a*b)%m,龟速乘
{
    a %= m;
    b %= m;
    ll res = 0;
    while (b) {
        if (b & 1)
            res = (res + a) % m;
        a = (a <<= 1) % m;
        b >>= 1;
    }
    return res % m;
}
bool Witness(ll a, ll n, ll x, ll sum)
{
    ll judge = quick_pow(a, x, n);
    if (judge == n - 1 || judge == 1)
        return 1;

    while (sum--) {
        judge = Mult_Mod(judge, judge, n);
        if (judge == n - 1)
            return 1;
    }
    return 0;
}
bool Miller_Rabin(ll n)
{
    if (n < 2)
        return 0;
    if (n == 2)
        return 1;
    if ((n & 1) == 0)
        return 0;

    ll x = n - 1, sum = 0;
    while (x % 2 == 0) {
        x >>= 1;
        sum++;
    }
    int times = 20;
    for (ll i = 1; i <= times; i++) {
        ll a = rand() % (n - 1) + 1; //取与p互质的整数a
        if (!Witness(a, n, x, sum)) //费马小定理的随机数检验
            return 0;
    }
    return 1;
}

除法分块

/**
 * 除法分块
 * ans=k%1+k%2+k%3+....k%n
 * */
for (long long l = 1, r; l <= n; l = r + 1) {
    r = (k / l == 0) ? n : min(k / (k / l), n);
    ans -= (l + r) * (r - l + 1) / 2 * (k / l);
}

求质因子

/**
 * 求一个数的质因子
 * n^(1/2)
 * 使用时,对set内的数在进行一次判断素数
 * */
int is_prime(ll x)
{
    if (x == 1)
        return 0;
    for (ll i = 2; i * i <= x; i++)
        if (x % i == 0)
            return 0;
    return 1;
}
void solve(set& s)
{
    for (ll i = 1; i * i <= x; i++)
        if (x % i == 0)
            s.insert(i), s.insert(x / i);
}


/**
 * Pollard_Rho筛素因子
 * */
ll Pollard_Rho(ll n, ll c) //寻找一个因子
{
    ll i = 1, k = 2;
    ll x = rand() % n; //产生随机数x0(并控制其范围在1 ~ x-1之间)
    ll y = x;
    while (1) {
        i++;
        x = (Mult_Mod(x, x, n) + c) % n;
        ll g = gcd(y - x, n);
        if (g < 0)
            g = -g;
        if (g > 1 && g < n)
            return g;
        if (y == x)
            return n;
        if (i == k) {
            y = x;
            k <<= 1;
        }
    }
}
int total; //因子的个数
ll factor[MAXN];
void Find_fac(ll n) //对n进行素因子分解,存入factor
{
    if (Miller_Rabin(n)) { //是素数就把这个素因子存起来
        factor[++total] = n;
        return;
    }
    long long p = n;
    while (p >= n) //值变化,防止陷入死循环k
        p = Pollard_Rho(p, rand() % (n - 1) + 1);
    Find_fac(n / p);
    Find_fac(p);
}

素数个数

好像是求1亿内素数个数的解法

typedef long long LL;
const int N = 5e6 + 2;
bool np[N];
int prime[N], pi[N];
int getprime()
{
    int cnt = 0;
    np[0] = np[1] = true;
    pi[0] = pi[1] = 0;
    for (int i = 2; i < N; ++i) {
        if (!np[i])
            prime[++cnt] = i;
        pi[i] = cnt;
        for (int j = 1; j <= cnt && i * prime[j] < N; ++j) {
            np[i * prime[j]] = true;
            if (i % prime[j] == 0)
                break;
        }
    }
    return cnt;
}
const int M = 7;
const int PM = 2 * 3 * 5 * 7 * 11 * 13 * 17;
int phi[PM + 1][M + 1], sz[M + 1];
void init()
{
    getprime();
    sz[0] = 1;
    for (int i = 0; i <= PM; ++i)
        phi[i][0] = i;
    for (int i = 1; i <= M; ++i) {
        sz[i] = prime[i] * sz[i - 1];
        for (int j = 1; j <= PM; ++j) {
            phi[j][i] = phi[j][i - 1] - phi[j / prime[i]][i - 1];
        }
    }
}
int sqrt2(LL x)
{
    LL r = (LL)sqrt(x - 0.1);
    while (r * r <= x)
        ++r;
    return int(r - 1);
}
int sqrt3(LL x)
{
    LL r = (LL)cbrt(x - 0.1);
    while (r * r * r <= x)
        ++r;
    return int(r - 1);
}
LL getphi(LL x, int s)
{
    if (s == 0)
        return x;
    if (s <= M)
        return phi[x % sz[s]][s] + (x / sz[s]) * phi[sz[s]][s];
    if (x <= prime[s] * prime[s])
        return pi[x] - s + 1;
    if (x <= prime[s] * prime[s] * prime[s] && x < N) {
        int s2x = pi[sqrt2(x)];
        LL ans = pi[x] - (s2x + s - 2) * (s2x - s + 1) / 2;
        for (int i = s + 1; i <= s2x; ++i) {
            ans += pi[x / prime[i]];
        }
        return ans;
    }
    return getphi(x, s - 1) - getphi(x / prime[s], s - 1);
}
LL getpi(LL x)
{
    if (x < N)
        return pi[x];
    LL ans = getphi(x, pi[sqrt3(x)]) + pi[sqrt3(x)] - 1;
    for (int i = pi[sqrt3(x)] + 1, ed = pi[sqrt2(x)]; i <= ed; ++i) {
        ans -= getpi(x / prime[i]) - i + 1;
    }
    return ans;
}
LL lehmer_pi(LL x)
{
    if (x < N)
        return pi[x];
    int a = (int)lehmer_pi(sqrt2(sqrt2(x)));
    int b = (int)lehmer_pi(sqrt2(x));
    int c = (int)lehmer_pi(sqrt3(x));
    LL sum = getphi(x, a) + LL(b + a - 2) * (b - a + 1) / 2;
    for (int i = a + 1; i <= b; i++) {
        LL w = x / prime[i];
        sum -= lehmer_pi(w);
        if (i > c)
            continue;
        LL lim = lehmer_pi(sqrt2(w));
        for (int j = i; j <= lim; j++) {
            sum -= lehmer_pi(w / prime[j]) - (j - 1);
        }
    }
    return sum;
}
int main()
{
    init();
    LL n;
    while (cin >> n) {
        cout << lehmer_pi(n) << endl;
    }
    return 0;
}
posted @ 2021-04-03 22:36  CrossAutomaton  阅读(154)  评论(0编辑  收藏  举报