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;
}