ACM
[TOC]
定义
开头
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_cxx;
#define ll long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const double Pi = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e7 + 10;
快读
正常快读
inline int rd(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
读入挂
inline char nc() {
static char buf[100000], *p1, *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int rd(){
int x = 0; char ch = nc();
while (ch < '0' || ch>'9') {ch = nc(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = nc(); }
return x;
}
int128输入输出
void scan(__int128 &x)//输入
{
x = 0;
int f = 1;
char ch;
if((ch = getchar()) == '-') f = -f;
else x = x*10 + ch-'0';
while((ch = getchar()) >= '0' && ch <= '9')
x = x*10 + ch-'0';
x *= f;
}
void _print(__int128 x)
{
if (x > 9)
_print(x / 10);
putchar(x % 10 + '0');
}
void print(__int128 x) //输出
{
if (x < 0)
{
x = -x;
putchar('-');
}
_print(x);
}
优化
/* 开启优化的情况下未赋初始值的变量可能赋随机值 */
// O2优化
#pragma GCC optimize(2)
// O3优化
#pragma GCC optimize(3)
STL 黑科技
可持久化平衡树
#include <ext/rope>
using namespace __gnu_cxx;
rope<int> a;
rope<char> a;
a.push_back(x) // 在末尾插入
a.pop_back(x) // 删除最后一个元素
a.size() // 返回长度
a.insert(int pos, x) // 在pos插入x
a.erase(int pos, int sum) // 在pos删除sum个元素
a.replace(int pos, x) // 将pos替换为x
a.substr(int pos, int sum) // 在pos处截取sum个元素
a.at(x) a[x] //访问第x个元素
字符串
字符串哈希+二分最长公共前缀
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int maxn = 1e5 + 10;
const int N = 1e5 + 10;
const int P = 131;
ULL h[N], h2[N], p[N];
char s[maxn], s2[maxn];
int n;
void init()
{
n = strlen(s + 1);
for (int i = n; i >= 1; i--)
s2[n - i + 1] = s[i];
s2[n + 1] = '\0';
p[0] = 1;
for (int i = 1; i <= n; i++)
{
h[i] = h[i - 1] * P + s[i];
h2[i] = h2[i - 1] * P + s2[i];
p[i] = p[i - 1] * P;
}
}
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
ULL get_re(int l, int r)
{
swap(l, r);
l = n - l + 1;
r = n - r + 1;
return h2[r] - h2[l - 1] * p[r - l + 1];
}
signed main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%s", s + 1);
init();
int a[30] = {0};
for (int i = 1; i <= n; i++)
a[s[i] - 'a' + 1]++;
for (int i = 1; i <= 26; i++)
a[i] += a[i - 1];
int l = -1;
for (int i = 1; i <= n; i++)
{
if (a[s[i] - 'a'] > i - 1)
{
l = i;
break;
}
}
// cout << get(1, 3) << " " << get_re(5, 7) << endl;
// cout << l << endl;
if (l == -1)
{
printf("%s\n", s + 1);
continue;
}
int min_posr = n;
for (int i = n - 1; i > l; i--)
{
int len = i - l + 1;
int ll = 0, rr = len;
while (ll < rr)
{
int mid = ll + rr + 1 >> 1;
ULL hhash1 = get_re(min_posr - mid + 1, min_posr);
ULL hhash2 = get_re(i - mid + 1, i);
if (hhash1 == hhash2)
ll = mid;
else
rr = mid - 1;
}
if (ll != len)
{
if (s[min_posr - rr] > s[i - rr])
{
min_posr = i;
// cout << min_posr << "\n";
}
}
else
{
int len2 = min_posr - l - ll + 1;
int lll = 0, rrr = len2;
while (lll < rrr)
{
int mid = lll + rrr + 1 >> 1;
ULL hhash1 = get(l + ll, l + ll + mid - 1);
ULL hhash2 = get_re(min_posr - ll - mid + 1, min_posr - ll);
if (hhash1 == hhash2)
lll = mid;
else
rrr = mid - 1;
}
// cout << l << " " << ll << " " << min_posr << " " << lll << "\n";
// cout << l + ll + lll << " " << min_posr - ll - lll << "\n";
// cout << i << "\n";
if (s[l + ll - 1 + lll + 1] < s[min_posr - ll + 1 - lll - 1])
min_posr = i;
// cout << 1 << " \n";
}
}
for (int i = 1; i < l; i++)
printf("%c", s[i]);
for (int i = min_posr; i >= l; i--)
printf("%c", s[i]);
for (int i = min_posr + 1; i <= n; i++)
printf("%c", s[i]);
puts("");
}
}
后缀数组
const int maxn = 2e5 + 10;
// n:串长。
// m:字符集大小。
// s[0..n − 1] :字符串。
// sa[1..n] :字典序第 i 小的是哪个后缀。
// rank[0..n − 1] :后缀 i 的排名。
// height[i] :lcp(sa[i], sa[i − 1]),最长公共前缀。
int rk[maxn], sa[maxn], height[maxn], tmp[maxn], cnt[maxn];
char s[maxn];
void suffixarray(int &n, int m)
{
int i, j, k;
n++;
for (i = 0; i < n * 2 + 5; i++)
rk[i] = sa[i] = height[i] = tmp[i] = 0;
for (i = 0; i < m; i++)
cnt[i] = 0;
for (i = 0; i < n; i++)
cnt[rk[i] = s[i]]++;
for (i = 1; i < m; i++)
cnt[i] += cnt[i - 1];
for (i = 0; i < n; i++)
sa[--cnt[rk[i]]] = i;
for (k = 1; k <= n; k <<= 1)
{
for (i = 0; i < n; i++)
{
j = sa[i] - k;
if (j < 0)
j += n;
tmp[cnt[rk[j]]++] = j;
}
sa[tmp[cnt[0] = 0]] = j = 0;
for (i = 1; i < n; i++)
{
if (rk[tmp[i]] != rk[tmp[i - 1]] || rk[tmp[i] + k] != rk[tmp[i - 1] + k])
cnt[++j] = i;
sa[tmp[i]] = j;
}
memcpy(rk, sa, n * sizeof(int));
memcpy(sa, tmp, n * sizeof(int));
if (j >= n - 1)
break;
}
for (j = rk[height[i = k = 0] = 0]; i < n - 1; i++, k++)
while (~k && s[i] != s[sa[j - 1] + k])
height[j] = k--, j = rk[sa[j] + 1];
}
字典树
struct trie {
int nex[100000][26], cnt;
bool exist[100000]; // 该结点结尾的字符串是否存在
void insert(char *s, int l) { // 插入字符串
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!nex[p][c]) nex[p][c] = ++cnt; // 如果没有,就添加结点
p = nex[p][c];
}
exist[p] = 1;
}
bool find(char *s, int l) { // 查找字符串
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!nex[p][c]) return 0;
p = nex[p][c];
}
return exist[p];
}
};
AC自动机
#include <bits/stdc++.h>
using namespace std;
const int N = 156, L = 1e6 + 6;
namespace AC
{
const int SZ = N * 80;
int tot, tr[SZ][26];
int fail[SZ], idx[SZ], val[SZ];
int cnt[N]; // 记录第 i 个字符串的出现次数
void init()
{
memset(fail, 0, sizeof(fail));
memset(tr, 0, sizeof(tr));
memset(val, 0, sizeof(val));
memset(cnt, 0, sizeof(cnt));
memset(idx, 0, sizeof(idx));
tot = 0;
}
void insert(char *s, int id)
{ // id 表示原始字符串的编号
int u = 0;
for (int i = 1; s[i]; i++)
{
if (!tr[u][s[i] - 'a'])
tr[u][s[i] - 'a'] = ++tot;
u = tr[u][s[i] - 'a']; // 转移
}
idx[u] = id; // 以 u 为结尾的字符串编号为 idx[u]
}
queue<int> q;
void build()
{
for (int i = 0; i < 26; i++)
if (tr[0][i])
q.push(tr[0][i]);
while (q.size())
{
int u = q.front();
q.pop();
for (int i = 0; i < 26; i++)
{
if (tr[u][i])
{
fail[tr[u][i]] =
tr[fail[u]][i]; // fail数组:同一字符可以匹配的其他位置
q.push(tr[u][i]);
}
else
tr[u][i] = tr[fail[u]][i];
}
}
}
int query(char *t)
{ // 返回最大的出现次数
int u = 0, res = 0;
for (int i = 1; t[i]; i++)
{
u = tr[u][t[i] - 'a'];
for (int j = u; j; j = fail[j])
val[j]++;
}
for (int i = 0; i <= tot; i++)
if (idx[i])
res = max(res, val[i]), cnt[idx[i]] = val[i];
return res;
}
} // namespace AC
int n;
char s[N][100], t[L];
int main()
{
while (~scanf("%d", &n))
{
if (n == 0)
break;
AC::init(); // 数组清零
for (int i = 1; i <= n; i++)
scanf("%s", s[i] + 1), AC::insert(s[i], i); // 需要记录该字符串的序号
AC::build();
scanf("%s", t + 1);
int x = AC::query(t);
printf("%d\n", x);
for (int i = 1; i <= n; i++)
if (AC::cnt[i] == x)
printf("%s\n", s[i] + 1);
}
return 0;
}
数据结构
线段树
struct Seg {
int t[maxn << 2], tag[maxn << 2];
void up(int id) {
t[id] = t[id << 1]+t[id << 1 | 1];
}
void build(int id, int l, int r) {
t[id] = 0;
tag[id] = 0;
if (l == r) return;
int mid = l + r >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void down(int id) {
if (!tag[id]) return;
tag[id << 1 | 1] += tag[id];
tag[id << 1] += tag[id];
t[id << 1] += tag[id];
t[id << 1 | 1] += tag[id];
tag[id] = 0;
}
void modify(int id, int l, int r, int ql, int qr, int v) {
if (l >= ql && r <= qr) {
tag[id] += v;
t[id] += v;
return;
}
down(id);
int mid = l + r >> 1;
if (ql <= mid) modify(id << 1, l, mid, ql, qr, v);
if (qr > mid) modify(id << 1 | 1, mid + 1, r, ql, qr, v);
up(id);
}
int query(int id, int l, int r) {
if (t[id]) return -1;
if (l == r) return l;
down(id);
int mid = l + r >> 1;
if (!t[id << 1]) return query(id << 1, l, mid);
else return query(id << 1 | 1, mid + 1, r);
}
// int find(int id, int l, int r, int p) {
//
// }
}seg;
typedef long long ll;
const int maxn = 3e5 + 10;
int a[maxn];
struct Tree
{
int l, r;
ll sum;
};
struct Seg
{
Tree t[maxn << 2];
inline void up(int id) { t[id].sum = t[id << 1].sum + t[id << 1 | 1].sum; }
void build(int id, int l, int r)
{
t[id].l = l;
t[id].r = r;
if (l == r)
{
t[id].sum = a[l];
return;
}
int mid = l + r >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
up(id);
}
void update(int id, int ql, int qr, int v)
{
if (t[id].l == t[id].r)
{
t[id].sum += v;
return;
}
int mid = t[id].l + t[id].r >> 1;
if (ql <= mid)
update(id << 1, ql, qr, v);
if (qr > mid)
update(id << 1 | 1, ql, qr, v);
up(id);
}
ll query(int id, int l, int r)
{
if (l <= t[id].l && t[id].r <= r)
return t[id].sum;
int mid = (t[id].l + t[id].r) >> 1;
if (l > mid)
return query(id << 1 | 1, l, r);
else if (r <= mid)
return query(id << 1, l, r);
else
return query(id << 1, l, r) + query(id << 1 | 1, l, r);
}
} seg;
区间合并
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn];
struct Tree
{
int l, r;
int lenl, lenr;
ll sum;
int sz;
};
struct Seg
{
Tree t[maxn << 2];
void up(int id)
{
t[id] = merge(t[id << 1], t[id << 1 | 1]);
}
Tree merge(Tree x, Tree y)
{
Tree tmp;
tmp.sz = x.sz + y.sz;
tmp.l = x.l;
tmp.r = y.r;
tmp.sum = x.sum + y.sum + (a[x.r] <= a[y.l] ? (ll)x.lenr * y.lenl : 0);
tmp.lenl = x.lenl + (x.lenl == x.sz && a[x.r] <= a[y.l] ? y.lenl : 0);
tmp.lenr = y.lenr + (y.lenr == y.sz && a[x.r] <= a[y.l] ? x.lenr : 0);
return tmp;
}
void build(int id, int l, int r)
{
t[id].l = l;
t[id].r = r;
if (l == r)
{
t[id].lenl = t[id].lenr = 1;
t[id].sum = 1;
t[id].sz = 1;
return;
}
int mid = l + r >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
up(id);
}
void update(int id, int l, int r)
{
if (t[id].l == t[id].r)
return;
int mid = (t[id].l + t[id].r) >> 1;
if (l <= mid)
update(id << 1, l, r);
else
update(id << 1 | 1, l, r);
up(id);
}
Tree query(int id, int l, int r)
{
if (l <= t[id].l && t[id].r <= r)
return t[id];
int mid = (t[id].l + t[id].r) >> 1;
if (l > mid)
return query(id << 1 | 1, l, r);
else if (r <= mid)
return query(id << 1, l, r);
else
return merge(query(id << 1, l, r), query(id << 1 | 1, l, r));
}
} seg;
珂朵莉树
#include <bits/stdc++.h>
using namespace std;
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using ll = long long;
#define all(x) std::begin(x), std::end(x)
inline ll mul(ll a, ll b, ll p)
{
return static_cast<__int128_t>(a) * b % p;
}
inline ll power(ll a, ll i, ll p)
{
ll res = 1;
while (i)
{
if (i & 1)
res = mul(res, a, p);
a = mul(a, a, p);
i >>= 1;
}
return res;
}
class ODT
{
private:
struct Node
{
int l, r;
mutable ll val;
Node(int l = 0, int r = 0, ll val = 0) : l(l), r(r), val(val) {}
bool operator<(const Node &a) const
{
return l < a.l;
}
};
set<Node> odt;
public:
void insert(int l, int r, ll val)
{
odt.insert(Node(l, r, val));
}
auto split(int pos)
{
auto it = odt.lower_bound(Node(pos));
if (it != odt.end() && it->l == pos)
return it;
--it;
int l = it->l, r = it->r;
ll val = it->val;
odt.erase(it);
odt.insert(Node(l, pos - 1, val));
return odt.insert(Node(pos, r, val)).first;
}
void assign(int l, int r, ll val)
{
auto end = split(r + 1), begin = split(l);
odt.erase(begin, end);
odt.insert(Node(l, r, val));
}
void work(int l, int r, ...)
{
auto itr = split(r + 1), itl = split(l);
for (; itl != itr; ++itl)
{
// work
}
}
void add(int l, int r, ll k)
{ // 暴力拿出区间求和
auto itr = split(r + 1), itl = split(l);
for (; itl != itr; ++itl)
{
itl->val += k;
}
}
ll rank(int l, int r, int kth)
{ // 暴力排序,一个一个数
vector<pair<ll, int>> v;
auto itr = split(r + 1), itl = split(l);
for (; itl != itr; ++itl)
{
v.push_back({itl->val, itl->r - itl->l + 1});
}
sort(all(v), [](const pair<ll, int> &a, const pair<ll, int> &b)
{ return a.first != b.first ? a.first < b.first : a.second < b.second; });
for (const auto &[val, cnt] : v)
{
kth -= cnt;
if (kth <= 0)
{
return val;
}
}
return -1;
}
ll sum(int l, int r, ll k, ll p)
{ // 暴力拿出区间,一个一个计算
ll res = 0;
auto itr = split(r + 1), itl = split(l);
for (; itl != itr; ++itl)
{
res = (res + mul(power(itl->val, k, p), itl->r - itl->l + 1, p)) % p;
}
return res;
}
};
ODT odt;
主席树
// 洛谷P3834
#include <bits/stdc++.h>
using namespace std;
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int maxn = 2e5 + 10;
int rt[maxn], tot = 0;
int a[maxn], b[maxn];
unordered_map<int, int> mp;
struct Tree
{
int lson, rson;
int sum;
};
struct Seg
{
Tree t[maxn * 40];
void up(int id)
{
t[id].sum = t[t[id].lson].sum + t[t[id].rson].sum;
}
void build(int &id, int l, int r)
{
if (!id)
id = ++tot;
if (l == r)
return;
int mid = l + r >> 1;
build(t[id].lson, l, mid);
build(t[id].rson, mid + 1, r);
}
void update(int pre, int &id, int pos, int l, int r)
{
if (!id)
id = ++tot;
if (l == r)
{
t[id].sum = t[pre].sum + 1;
return;
}
int mid = l + r >> 1;
if (pos <= mid)
{
t[id].rson = t[pre].rson;
update(t[pre].lson, t[id].lson, pos, l, mid);
}
else
{
t[id].lson = t[pre].lson;
update(t[pre].rson, t[id].rson, pos, mid + 1, r);
}
up(id);
}
int query(int pre, int id, int k, int l, int r)
{
if (l == r)
return l;
int tmp_sum = t[t[id].lson].sum - t[t[pre].lson].sum;
int mid = l + r >> 1;
if (k <= tmp_sum)
return query(t[pre].lson, t[id].lson, k, l, mid);
else
return query(t[pre].rson, t[id].rson, k - tmp_sum, mid + 1, r);
}
} seg;
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i], b[i] = a[i];
sort(b + 1, b + 1 + n);
int num = unique(b + 1, b + 1 + n) - (b + 1);
seg.build(rt[0], 1, num);
for (int i = 1; i <= num; i++)
mp[b[i]] = i;
for (int i = 1; i <= n; i++)
seg.update(rt[i - 1], rt[i], mp[a[i]], 1, num);
while (m--)
{
int l, r, k;
cin >> l >> r >> k;
cout << b[seg.query(rt[l - 1], rt[r], k, 1, num)] << "\n";
}
}
signed main()
{
FAST;
int t = 1;
while (t--)
solve();
}
// codeforces 961E
#include <bits/stdc++.h>
using namespace std;
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define int long long
const int maxn = 2e5 + 10;
int a[maxn], b[maxn];
unordered_map<int, int> mp;
int rt[maxn], tot = 0;
struct Tree
{
int lson, rson;
int sum;
};
struct Seg
{
Tree t[maxn << 5];
void up(int id)
{
t[id].sum = t[t[id].lson].sum + t[t[id].rson].sum;
}
void build(int &id, int l, int r)
{
if (!id)
id = ++tot;
if (l == r)
{
t[id].sum = 0;
return;
}
int mid = l + r >> 1;
build(t[id].lson, l, mid);
build(t[id].rson, mid + 1, r);
}
void update(int pre, int &id, int pos, int l, int r)
{
if (!id)
id = ++tot;
if (l == r)
{
t[id].sum = t[pre].sum + 1;
return;
}
int mid = l + r >> 1;
if (pos <= mid)
{
t[id].rson = t[pre].rson;
update(t[pre].lson, t[id].lson, pos, l, mid);
}
else
{
t[id].lson = t[pre].lson;
update(t[pre].rson, t[id].rson, pos, mid + 1, r);
}
up(id);
}
int query(int pre, int id, int l, int r, int L, int R)
{
if (L <= l && r <= R)
return t[id].sum - t[pre].sum;
int mid = l + r >> 1;
if (R <= mid)
return query(t[pre].lson, t[id].lson, l, mid, L, R);
else if (L > mid)
return query(t[pre].rson, t[id].rson, mid + 1, r, L, R);
else
return query(t[pre].lson, t[id].lson, l, mid, L, R) + query(t[pre].rson, t[id].rson, mid + 1, r, L, R);
}
} seg;
void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], b[i] = a[i];
sort(b + 1, b + 1 + n);
int num = unique(b + 1, b + 1 + n) - (b + 1);
seg.build(rt[n + 1], 1, num);
for (int i = 1; i <= num; i++)
mp[b[i]] = i;
for (int i = n; i >= 1; i--)
seg.update(rt[i + 1], rt[i], mp[a[i]], 1, num);
int ans = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] > i)
{
int l = lower_bound(b + 1, b + 1 + num, i) - b;
ans += seg.query(rt[min(n + 1, a[i] + 1)], rt[i + 1], 1, num, l, num);
}
}
cout << ans << "\n";
}
signed main()
{
FAST;
int t = 1;
while (t--)
solve();
}
可持久化并查集
// 洛谷P3402
#include <bits/stdc++.h>
using namespace std;
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int maxn = 2e5 + 10;
int tot, rt[maxn * 40];
int n;
struct TreeNode
{
int fa, dep;
int lson, rson;
};
struct Seg
{
TreeNode t[maxn * 40];
void build(int &id, int l, int r)
{
if (!id)
id = ++tot;
if (l == r)
{
t[id].fa = l;
return;
}
int mid = l + r >> 1;
build(t[id].lson, l, mid);
build(t[id].rson, mid + 1, r);
}
void change(int pre, int &id, int l, int r, int pos, int v)
{
id = ++tot;
if (l == r)
{
t[id].fa = v, t[id].dep = t[pre].dep;
return;
}
int mid = l + r >> 1;
if (pos <= mid)
{
t[id].rson = t[pre].rson;
change(t[pre].lson, t[id].lson, l, mid, pos, v);
}
else
{
t[id].lson = t[pre].lson;
change(t[pre].rson, t[id].rson, mid + 1, r, pos, v);
}
}
void update(int id, int l, int r, int pos)
{
if (l == r)
{
t[id].dep++;
return;
}
int mid = l + r >> 1;
if (pos <= mid)
update(t[id].lson, l, mid, pos);
else
update(t[id].rson, mid + 1, r, pos);
}
int query(int id, int l, int r, int pos)
{
if (l == r)
return id;
int mid = l + r >> 1;
if (pos <= mid)
return query(t[id].lson, l, mid, pos);
else
return query(t[id].rson, mid + 1, r, pos);
}
int find(int now, int x)
{
int node = query(rt[now], 1, n, x);
return t[node].fa == x ? node : find(now, t[node].fa);
}
void merge(int now, int x, int y)
{
int nodex = find(now, x), nodey = find(now, y);
if (t[nodex].fa == t[nodey].fa)
return;
if (t[nodex].dep > t[nodey].dep)
swap(nodex, nodey);
change(rt[now - 1], rt[now], 1, n, t[nodex].fa, t[nodey].fa);
if (t[nodex].dep == t[nodey].dep)
update(rt[now], 1, n, t[nodey].fa);
}
} seg;
void solve()
{
int m;
cin >> n >> m;
seg.build(rt[0], 1, n);
for (int i = 1; i <= m; i++)
{
int op, x, y;
cin >> op;
rt[i] = rt[i - 1];
if (op == 1)
{
cin >> x >> y;
seg.merge(i, x, y);
}
else if (op == 2)
{
cin >> x;
rt[i] = rt[x];
}
else
{
cin >> x >> y;
cout << (seg.find(i, x) == seg.find(i, y) ? 1 : 0) << "\n";
}
}
}
signed main()
{
FAST;
int t = 1;
while (t--)
solve();
}
LCA
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int n, m, s;
struct lca
{
int cnt, head[maxn];
struct edge
{
int to, next;
} e[maxn << 1];
void add(int u, int v)
{
e[++cnt] = {v, head[u]};
head[u] = cnt;
e[++cnt] = {u, head[v]};
head[v] = cnt;
}
int dep[maxn];
int lg[maxn];
int fa[maxn][22];
void init()
{
for (int i = 1; i <= maxn; ++i)
{
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
// cout << i << " -> " << lg[i] << endl;
}
}
void dfs(int now, int pre)
{
fa[now][0] = pre;
dep[now] = dep[pre] + 1;
for (int i = 1; i <= lg[dep[now]]; ++i)
fa[now][i] = fa[fa[now][i - 1]][i - 1];
for (int i = head[now]; i; i = e[i].next)
if (e[i].to != pre)
dfs(e[i].to, now);
}
int LCA(int x, int y)
{
if (dep[x] < dep[y])
swap(x, y);
while (dep[x] > dep[y])
x = fa[x][lg[dep[x] - dep[y]] - 1];
if (x == y)
return x;
for (int k = lg[dep[x]] - 1; k >= 0; --k)
if (fa[x][k] != fa[y][k])
x = fa[x][k], y = fa[y][k];
return fa[x][0];
}
} lca;
int main () {
scanf("%d%d%d", &n, &m, &s);
for (int i = 1; i < n; ++i) {
int x, y;
scanf("%d%d", &x, &y);
lca.add(x, y);
}
lca.init();
lca.dfs(s, 0);
for (int i = 1; i <= m; ++i) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", lca.LCA(x, y));
}
return 0;
}
扫描线
#include <algorithm>
#include <cstdio>
#include <cstring>
#define maxn 300
using namespace std;
int lazy[maxn << 3]; // 标记了这条线段出现的次数
double s[maxn << 3];
struct node1 {
double l, r;
double sum;
} cl[maxn << 3]; // 线段树
struct node2 {
double x, y1, y2;
int flag;
} p[maxn << 3]; // 坐标
// 定义sort比较
bool cmp(node2 a, node2 b) { return a.x < b.x; }
// 上传
void pushup(int rt) {
if (lazy[rt] > 0)
cl[rt].sum = cl[rt].r - cl[rt].l;
else
cl[rt].sum = cl[rt * 2].sum + cl[rt * 2 + 1].sum;
}
// 建树
void build(int rt, int l, int r) {
if (r - l > 1) {
cl[rt].l = s[l];
cl[rt].r = s[r];
build(rt * 2, l, (l + r) / 2);
build(rt * 2 + 1, (l + r) / 2, r);
pushup(rt);
} else {
cl[rt].l = s[l];
cl[rt].r = s[r];
cl[rt].sum = 0;
}
return;
}
// 更新
void update(int rt, double y1, double y2, int flag) {
if (cl[rt].l == y1 && cl[rt].r == y2) {
lazy[rt] += flag;
pushup(rt);
return;
} else {
if (cl[rt * 2].r > y1) update(rt * 2, y1, min(cl[rt * 2].r, y2), flag);
if (cl[rt * 2 + 1].l < y2)
update(rt * 2 + 1, max(cl[rt * 2 + 1].l, y1), y2, flag);
pushup(rt);
}
}
int main() {
int temp = 1, n;
double x1, y1, x2, y2, ans;
while (scanf("%d", &n) && n) {
ans = 0;
for (int i = 0; i < n; i++) {
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
p[i].x = x1;
p[i].y1 = y1;
p[i].y2 = y2;
p[i].flag = 1;
p[i + n].x = x2;
p[i + n].y1 = y1;
p[i + n].y2 = y2;
p[i + n].flag = -1;
s[i + 1] = y1;
s[i + n + 1] = y2;
}
sort(s + 1, s + (2 * n + 1)); // 离散化
sort(p, p + 2 * n, cmp); // 把矩形的边的横坐标从小到大排序
build(1, 1, 2 * n); // 建树
memset(lazy, 0, sizeof(lazy));
update(1, p[0].y1, p[0].y2, p[0].flag);
for (int i = 1; i < 2 * n; i++) {
ans += (p[i].x - p[i - 1].x) * cl[1].sum;
update(1, p[i].y1, p[i].y2, p[i].flag);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n", temp++, ans);
}
return 0;
}
莫队
基础莫队
题意是寻找0~i,j~n中不同的数有多少个。
创建一个a[i]=a[i+n];的数组
理解为j~i+n中查询
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m,x,y,block;
int a[N*2],cnt[N*2],ans[N*2];
struct node{
int i;
int l;
int r;
} q[N*2];
void add(int x,int &res){
if(cnt[x]==0)
res++;
cnt[x]++;
}
void del(int x,int &res){
cnt[x]--;
if(cnt[x]==0)
res--;
}
bool cmp(node l,node r){
return l.l/block == r.l/block ? l.r < r.r : l.l/block < r.l/block;
}
int main(){
while(~scanf("%d %d",&n,&m)){
memset(cnt, 0, sizeof cnt);
for (int i = 1; i <= n;i++){
scanf("%d", &a[i]);
a[i + n] = a[i];
}
for (int i = 1; i <= m;i++){
scanf("%d %d", &x, &y);
q[i] = {i,y,x+n};
}
block = sqrt((double)n * n / m);
sort(q + 1, q + 1 + m, cmp);
for (int k = 1, i = 0, j = 0, res = 0; k <= m;k++){
int id = q[k].i;
int l = q[k].l;
int r = q[k].r;
while(i<r)
add(a[++i], res);
while(i>r)
del(a[i--], res);
while(j<l)
del(a[j++], res);
while(j>l)
add(a[--j], res);
ans[id] = res;
}
for (int i = 1; i <= m;i++){
printf("%d\n", ans[i]);
}
}
}
带修莫队
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
int n, m, block, csum = 0, tsum = 0;//csum表示查询次数,tsum表示有几个时间点
struct change
{
int x, old, now;
} chan[N];
struct node
{
int l;
int r;
int tim;
int id;
} q[N];
int a[N], qk[N], cnt[M], ans[N];
bool cmp(node x, node y)
{
return qk[x.l] == qk[y.l] ? (qk[x.r] == qk[y.r] ? x.tim < y.tim : x.r < y.r) : x.l < y.l;//先比较左区间,再比较右区间,再比较时间;
}
void add(int x, int &res)
{
if (cnt[x] == 0)
res++;
cnt[x]++;
}
void del(int x, int &res)
{
cnt[x]--;
if (cnt[x] == 0)
res--;
}
signed main()
{
scanf("%d %d", &n, &m);
block = pow(n, 2.0 / 3); //分块
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
qk[i] = (i - 1) / block + 1; //初始化分块区间,快速求得每个点属于哪块
}
for (int i = 1; i <= m; i++)
{
char s;
int x, y;
getchar();
scanf("%c", &s);
scanf("%d %d", &x, &y);
if (s == 'R')
{ //修改操作
chan[++tsum].x = x; //tsum记录第几次修改,x记录哪个点被修改,old记录原来颜色,now记录新颜色
chan[tsum].old = a[x];
chan[tsum].now = y;
a[x] = y; //修改颜色
}
else
{
q[++csum].l = x; //l记录区间左值
q[csum].r = y; //r记录区间右值
q[csum].tim = tsum; //tim记录时间戳
q[csum].id = csum; //ID记录第几次询问
}
}
sort(q + 1, q + 1 + csum, cmp);
int r = 0, l = 1, tim = tsum;
int res = 0;
for (int i = 1; i <= csum; i++)
{
//处理时间轴
while (q[i].tim > tim)
{
tim++;
int x = chan[tim].x;
if (l <= x && x <= r)
{
del(a[x], res);
add(chan[tim].now, res);
}
a[x] = chan[tim].now;
}
while (q[i].tim < tim)
{
int x = chan[tim].x;
if (l <= x && x <= r)
{
del(a[x], res);
add(chan[tim].old, res);
}
a[x] = chan[tim].old;
tim--;
}
//先处理x轴
while (r < q[i].r)
add(a[++r], res);
while (r > q[i].r)
del(a[r--], res);
while (l < q[i].l)
del(a[l++], res);
while (l > q[i].l)
add(a[--l], res);
ans[q[i].id] = res;
}
for (int i = 1; i <= csum; i++)
{
printf("%d\n", ans[i]);
}
}
二分图染色板子
#pragma warning(disable:4996)
#include <bits/stdc++.h>
//#define int long long
#define fast ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
typedef long long ll;
using namespace std;
const double PI = acos(-1);
const int N = 1e5 + 10;
const int mod =1e9+7;
int t;
int col[N];
int fa[N];
vector<int>ve[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool bit(int s) {
for (int i = 0; i <ve[s].size(); i++) {
int y = ve[s][i];
if (col[s] == col[y]) {
return false;
}
if (!col[y]) {
col[y] = 3 - col[s];
if (!bit(y)) {
return false;
}
}
}
return true;
}
signed main() {
fast;
cin >> t;
int ca = 1;
while (t--) {
int n, m, s;
cin >> n >> m >> s;
for (int i = 0; i < n; i++) {
ve[i].clear();
fa[i] = i;
col[i] = 0;
}
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
ve[x].push_back(y);
ve[y].push_back(x);
int X = find(x);
int Y = find(y);
if (X != Y) {
fa[X] = Y;
}
}
int judge =find(0);
bool flag = true;
for (int i = 0; i < n; i++) {
if (find(i) != judge) {
flag = false;
}
}
if (!flag) {
printf("Case %d: NO\n", ca++);
continue;
}
col[s] = 1;
if(bit(s))
printf("Case %d: NO\n", ca++);
else {
printf("Case %d: YES\n", ca++);
}
}
}
#pragma warning(disable:4996)
#include <bits/stdc++.h>
//#define int long long
#define fast ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
typedef long long ll;
using namespace std;
const double PI = acos(-1);
const int N = 5e5 + 10;
const int mod = 1e9 + 7;
int t;
int col[N];
int fa[N];
struct node{
int to;
int next;
}e[N];
int tot;
int head[N];
void add(int u, int v) {
e[tot].to = v;
e[tot].next = head[u];
head[u] = tot++;
e[tot].to = u;
e[tot].next = head[v];
head[v] = tot++;
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool bit(int u) {
for (int i = head[u]; i; i=e[i].next) {
int v = e[i].to;
if (col[u] == col[v]) {
return false;
}
if (!col[v]) {
col[v] = 3 - col[u];
if (!bit(v)) {
return false;
}
}
}
return true;
}
signed main() {
fast;
cin >> t;
int ca = 1;
while (t--) {
int n, m, s;
tot = 1;
cin >> n >> m >> s;
memset(e, 0, sizeof e);
memset(head, 0, sizeof head);
for (int i = 0; i < n; i++) {
fa[i] = i;
col[i] = 0;
}
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
add(x, y);
int X = find(x);
int Y = find(y);
if (X != Y) {
fa[X] = Y;
}
}
int judge = find(0);
bool flag = true;
for (int i = 0; i < n; i++) {
if (find(i) != judge) {
flag = false;
}
}
if (!flag) {
printf("Case %d: NO\n", ca++);
continue;
}
col[s] = 1;
if (bit(s))
printf("Case %d: NO\n", ca++);
else {
printf("Case %d: YES\n", ca++);
}
}
}
匈牙利算法板子
#pragma warning(disable:4996)
//#include <bits/stdc++.h>
#include<queue>
#include<map>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
//#define int long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
const int inf = 0x3f3f3f;
const int N = 5e4 + 100;
const double eps = 1e-8;
const double pi = acos(-1.0);
typedef long long ll;
using namespace std;
int t;
struct node {
int to;
int next;
}e[N];
int head[305], tot, mat[305], n, m, p, k, v;
bool vis[305];
void add(int u, int v) {
e[tot].to = v;
e[tot].next = head[u];
head[u] = tot++;
}
bool find(int u) {
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (!vis[v]) {
vis[v] = 1;
if (!mat[v] || find(mat[v])) {
mat[v] = u;
return true;
}
}
}
return false;
}
signed main() {
scanf("%d",&t);
while (t--) {
tot = 1;
bool flag = true;
memset(head, 0, sizeof head);
memset(mat, 0, sizeof mat);
scanf("%d %d", &p, &n);
for (int u = 1; u <= p; u++) {
scanf("%d",&k);
if (k == 0) {
flag = false;
}
for (int i = 1; i <= k; i++) {
scanf("%d",&v);
add(u, v);
}
}
int ans = 0;
if (!flag) {
printf("NO\n");
continue;
}
for (int i = 1; i <= p; i++) {
memset(vis, 0, sizeof vis);
if (find(i))ans++;
}
if (ans == p)printf("YES\n");
else printf("NO\n");
}
}
km算法n^3
int nx, ny;//两边的点数
ll g[N][N];//二分图描述
ll linker[N], lx[N], ly[N];//y 中各点匹配状态,x,y 中的点标号
ll slack[N];
bool visx[N], visy[N];
int pre[N];
void bfs(int k) {
int x, y = 0, yy = 0;
ll delta;
memset(pre, 0, sizeof pre);
for (int i = 1;i <= ny;i++)slack[i] = 1e13;
linker[y] = (ll)k;
while (1) {
x = linker[y];delta = 1e13;visy[y] = true;
for (int i = 1;i <= ny;i++) {
if (!visy[i]) {
if (slack[i] > lx[x] + ly[i] - g[x][i]) {
slack[i] = lx[x] + ly[i] - g[x][i];
pre[i] = y;
}
if (slack[i] < delta)delta = slack[i], yy = i;
}
}
for (int i = 0;i <= ny;i++) {
if (visy[i]) {
lx[linker[i]] -= delta;
ly[i] += delta;
}
else slack[i] -= delta;
}
y = yy;
if (linker[y] == -1)break;
}
while (y) {
linker[y] = linker[pre[y]];
y = pre[y];
}
}
ll KM() {
memset(linker, -1, sizeof linker);
memset(lx, 0, sizeof lx);
memset(ly, 0, sizeof ly);
for (int i = 1;i <= ny;i++) {
memset(visy, false, sizeof visy);
bfs(i);
}
ll res = 0;
for (int i = 1;i <= ny;i++)
if (linker[i] != -1)
res += g[linker[i]][i];
return res;
}
网络流
最小费用最大流
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
//算最大费用权值改为负即可
struct Dinic
{
struct Edge
{
int v, rev, cap, cos;
};
vector<Edge> G[maxn];
int dis[maxn], cur[maxn], vis[maxn], n, sp, tp;
// nn为总点数
void init(int nn)
{
n = nn;
for (int i = 0; i <= n; ++i)
G[i].clear();
}
void addedge(int u, int v, int cap, int cos)
{
G[u].push_back(Edge{v, (int)G[v].size(), cap, cos});
G[v].push_back(Edge{u, (int)G[u].size() - 1, 0, -cos});
}
int bfs()
{
queue<int> q;
for (int i = 0; i <= n; ++i)
dis[i] = inf, vis[i] = 0;
dis[sp] = 0, q.push(sp), vis[sp] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for (auto &e : G[u])
{
if (e.cap && dis[e.v] > dis[u] + e.cos)
{
dis[e.v] = dis[u] + e.cos;
if (!vis[e.v])
q.push(e.v), vis[e.v] = 1;
}
}
}
return dis[tp] != inf;
}
int dfs(int u, int flow)
{
if (u == tp || !flow)
return flow;
int ret = 0, tmp;
vis[u] = 1;
for (int &i = cur[u]; i < G[u].size(); ++i)
{
auto &e = G[u][i];
if (!vis[e.v] && dis[e.v] == dis[u] + e.cos && (tmp = dfs(e.v, min(e.cap, flow - ret))))
{
ret += tmp, e.cap -= tmp, G[e.v][e.rev].cap += tmp;
if (ret == flow)
{
vis[u] = 0;
return ret;
}
}
}
if (!ret)
vis[u] = 1;
return ret;
}
/*
* 直接调用获取最小费用和最大流
* 输入: s-源点,t-汇点
* 返回值: pair<int,int> 第一个是最小费用,第二个是最大流
*/
pair<int, int> mincostmaxflow(int s, int t)
{
sp = s, tp = t;
int mincost = 0, maxflow = 0;
while (bfs())
{
for (int i = 0; i <= n; ++i)
cur[i] = 0;
int f = dfs(sp, inf);
mincost += f * dis[tp];
maxflow += f;
}
return make_pair(mincost, maxflow);
}
} mcmf;
int a[maxn], b[maxn];
void solve()
{
int n, m;
scanf("%d%d", &n, &m);
mcmf.init(n + m + 5);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
int s = 0, t = n + m + 1;
for (int i = 1, u; i <= m; i++)
{
scanf("%d%d", &u, &b[i]);
mcmf.addedge(s, i, 1, 0);
mcmf.addedge(i, m + u, 1, 0);
mcmf.addedge(i, m + b[i], 1, 0);
}
for (int i = 1; i <= n; i++)
{
mcmf.addedge(m + i, t, a[i], 0);
mcmf.addedge(m + i, t, inf, 1);
}
auto ans = mcmf.mincostmaxflow(s, t);
printf("%d\n", ans.first);
for (int i = 1; i <= m; i++)
{
for (auto it : mcmf.G[i])
{
int v = it.v;
if (v > m + n)
continue;
if (v == m + b[i])
{
printf(it.cap ? "1" : "0");
break;
}
}
}
printf("\n");
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
solve();
}
最大流
#include <algorithm>
#include <iostream>
#include <math.h>
#include <queue>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define maxn 450
#define INF 0x3f3f3f3f
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
int d[maxn], cur[maxn];
bool vis[maxn];
void init(int n)
{
for (int i = 0; i < n; i++)
G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();
Q.pop();
for (int i = 0; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)
return a;
int flow = 0, f;
for (int &i = cur[x]; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)
break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
this->s = s;
this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
} a;
#include<algorithm>
#include<iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <math.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=505; //最大结点总个数
const int maxm=1000005; //最大边的总条数:注意要包括反向边个数,即总条数=正向边总条数*2
int s; //源点
int t; //汇点
int head[maxn]; //点u邻接表的第一条边
int cnt; //边的数量,从0开始编号
struct edge
{
int w; //边的流量(残量)
int to; //该边通向的结点v
int next; //点u邻接表的下一条边
}e[maxm];
void addedge(int u,int v,int w) //添加一条u->v,最大容量为w的边
{
//建立正向边
e[cnt].w=w;
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
cnt++;
//建立反向边
e[cnt].w=0; //有些图是需要建立双向边(例如求最小割时),则反向边的初始残量不为0
e[cnt].to=u;
e[cnt].next=head[v];
head[v]=cnt;
cnt++;
}
int dis[maxn]; //dis数组记录层次
bool bfs() //利用BFS建立分成图,从而可以多次DFS增广
{
memset(dis,-1,sizeof(dis)); //初始化dis数组
queue<int> q;
q.push(s);
dis[s]=0; //源点层次为0
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(e[i].w>0&&dis[v]==-1) //可达&&未分层
{
dis[v]=dis[u]+1; //分层
if(v==t) //若到达汇点,则分层结束,返回true
return true;
q.push(v);
}
}
}
return false; //运行到此处,说明汇点已不可达,返回false
}
int cur[maxn]; //弧优化:cur数组用于记录上一次DFS增广时u已经增广到第几条边,从而优化时间
int dfs(int u,int flow) //flow代表流入u点的最大流量
{
if(u==t)
return flow; //到达汇点,直接返回flow
for(int &i=cur[u];i!=-1;i=e[i].next)
{ //注意i前面用&引用,这样就可以直接改变cur[u]
int v=e[i].to;
if(dis[v]==dis[u]+1&&e[i].w>0) //v为u的下一层&&可达
{
int k=dfs(v,min(flow,e[i].w));
if(k>0)
{
e[i].w-=k; //正向边-=k
e[i^1].w+=k; //反向边+=k
return k;
}
}
}
return 0; //无法继续增广,返回0
}
int dinic()
{
int ans=0; //记录总流量
while(bfs()) //分层
{
for(int i=0;i<maxn;i++) //初始化cur数组,即将head数组赋给cur数组
cur[i]=head[i];
while(int k=dfs(s,INF)) //增广
ans+=k;
}
return ans;
}
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
inline void addl(int u,int v,int w)
{
edge[cnt].e=v;
edge[cnt].v=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
void datasetting()
{
memset(head,-1,sizeof(head));
n=read();m=read();x=read();
int a,b,c;
for(int i=0;i<m;i++)
{
a=read();b=read();c=read();
addl(a,b,c);addl(b,a,0);
}
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
dis[1]=0;
queue<int>q;
q.push(1);
while(!q.empty())
{
int r=q.front();q.pop();
for(int i=head[r];i!=-1;i=edge[i].nxt)
{
int j=edge[i].e;
if(dis[j]==-1&&edge[i].v)
{
dis[j]=dis[r]+1;
q.push(j);
}
}
}
return dis[n]!=-1;//若不可以到终点(起点)就返回false
}
int dfs(int u,int flo)//dfs就是求节点u在残量为flo时的最大增量
{
if(u==n)return flo;
int detla=flo;
for(int i=cur[u];i!=-1;i=edge[i].nxt)
{
cur[u]=edge[i].nxt;
int v=edge[i].e;
if(dis[v]==(dis[u]+1)&&(edge[i].v)>0)
{
int d=dfs(v,min(detla,edge[i].v));
edge[i].v-=d;edge[i ^ 1].v+=d;
detla-=d;
if(detla==0)break;
}
}
return flo-detla;//返回这个点已经被允许流过的流量
}
int dini()
{
int ans=0;
while(bfs())
{
for(int i=1;i<=n;i++)cur[i]=head[i];
ans+=dfs(1,INF);
}
return ans;
}
数学
数论分块
快速计算形如\sum_{1=1}^nf(i)g(\left\lfloor\dfrac ni\right\rfloor)的和式
for (int l = 1, r = 0; l <= n; l = r + 1)
{
r = n / (n / l);
ans += (r - (l - 1)) * (n / l);
}
欧拉函数
线性筛(同时得到欧拉函数和素数表)
const int MAXN = 10000000;
bool check[MAXN + 10];
int phi[MAXN + 10];
int prime[MAXN + 10];
int tot; //素数的个数
void phi_and_prime_table(int N)
{
memset(check, false, sizeof(check));
phi[1] = 1;
tot = 0;
for (int i = 2; i <= N; i++)
{
if (!check[i])
{
prime[tot++] = i;
phi[i] = i - 1;
}
for (int j = 0; j < tot; j++)
{
if (i * prime[j] > N)
break;
check[i * prime[j]] = true;
if (i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else
{
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
}
求单个数的欧拉函数
long long eular(long long n)
{
long long ans = n;
for (int i = 2; i * i <= n; i++)
{
if (n % i == 0)
{
ans -= ans / i;
while (n % i == 0)
n /= i;
}
}
if (n > 1)
ans -= ans / n;
return ans;
}
模拟退火
void solve()
{
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); //高质量随机
double T = 100, delta = 0.98;
double x = 50;
double ans = f(x);
while (T > eps)
{
double a = rng() % 2;
if (a == 0)
a = -1;
double nx = x + a * T;
if (nx >= 0 && nx <= 100 && f(nx) < ans)
{
ans = f(nx);
x = nx;
}
T *= delta;
}
printf("%.4f\n", ans);
}
Lucas
int f[N];
int mod = 1e9 + 7;
// int mul(int a, int b, int p)
// {
// int ans = 0;
// for (; b; b >>= 1, a = (a + a) % p)
// if (b & 1)
// ans = (ans + a) % p;
// return ans;
// }
int qpow(int a, int b, int mod)
{
int ans = 1;
for (; b; b >>= 1, a = a * a % mod)
if (b & 1)
ans = ans * a % mod;
return ans;
}
void init()
{
for (int i = 1; i <= 1e6 + 10; i++)
{
f[i] = qpow(i, mod - 2, mod);
}
}
int c(int n, int m)
{
if (n < m)
return 0;
int ans = 1;
for (int i = 1; i <= m; i++)
{
ans = ans * (((n - m + i) % mod) * f[i] % mod) % mod;
}
return ans;
}
int lucas(int m, int n)
{
if (m == 0)
return 1;
return (lucas(n / mod, m / mod) * c(n % mod, m % mod)) % mod;
}
FFT和NTT
const long double PI = acos(-1.0);
const int MOD = (int)1e9 + 7;
inline int mul(int a,int b){
int res = (ll)a * b % MOD;
if(res < 0) res += MOD;
return res;
}
inline void add(int &a,int b){
a += b;
if(a >= MOD) a -= MOD;
}
inline void sub(int &a,int b){
a -= b;
if(a < 0) a += MOD;
}
const int Maxn = 5e5 + 5;
const double Pi=acos(-1);
struct CP
{
CP (double xx=0,double yy=0){x=xx,y=yy;}
double x,y;
CP operator + (CP const &B) const
{return CP(x+B.x,y+B.y);}
CP operator - (CP const &B) const
{return CP(x-B.x,y-B.y);}
CP operator * (CP const &B) const
{return CP(x*B.x-y*B.y,x*B.y+y*B.x);}
}f[Maxn * 3],p[Maxn * 3];
int tr[Maxn * 3];
int n,m;
void fft(CP *f,bool flag)
{
for (int i=0;i<n;i++)
if (i<tr[i])swap(f[i],f[tr[i]]);
//枚举区间长度
for(int p=2;p<=n;p<<=1){
int len=p>>1;//待合并的长度
CP tG(cos(2*Pi/p),sin(2*Pi/p));
if(!flag)tG.y*=-1;//p次单位根
for(int k=0;k<n;k+=p){//枚举起始点
CP buf(1,0);//遍历一个子问题并合并
for(int l=k;l<k+len;l++){
CP tt=buf*f[len+l];
f[len+l]=f[l]-tt;
f[l]=f[l]+tt;
buf=buf*tG;
}
}
}
}
class NTTClass{
public:
static const int MAXL=22;
static const int MAXN=1<<MAXL;
static const int root=3;
static const int MOD=998244353;
int rev[MAXN];
int fast_pow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%MOD;
a=1ll*a*a%MOD;
b>>=1;
}
return ans;
}
void transform(int n,int *t,int typ){
for(int i=0;i<n;i++)
if(i<rev[i])swap(t[i],t[rev[i]]);
for(int step=1;step<n;step<<=1){
int gn=fast_pow(root,(MOD-1)/(step<<1));
for(int i=0;i<n;i+=(step<<1)){
int g=1;
for(int j=0;j<step;j++,g=1ll*g*gn%MOD){
int x=t[i+j],y=1ll*g*t[i+j+step]%MOD;
t[i+j]=(x+y)%MOD;
t[i+j+step]=(x-y+MOD)%MOD;
}
}
}
if(typ==1)return;
for(int i=1;i<n/2;i++)swap(t[i],t[n-i]);
int inv=fast_pow(n,MOD-2);
for(int i=0;i<n;i++)t[i]=1ll*t[i]*inv%MOD;
}
void ntt(int p,int *A,int *B,int *C){
transform(p,A,1);
transform(p,B,1);
for(int i=0;i<p;i++)C[i]=1ll*A[i]*B[i]%MOD;
transform(p,C,-1);
}
void mul(int *A,int *B,int *C,int n,int m) {
int p=1,l=0;
while(p<=n+m)p<<=1,l++;
//printf("n = %d, m = %d\n",n,m);
for (int i=n+1;i<p;i++) A[i] = 0;
for (int i=m+1;i<p;i++) B[i] = 0;
//for (int i=0;i<p;i++) printf("%d ",A[i]);puts("");
//for (int i=0;i<p;i++) printf("%d ",B[i]);puts("");
for(int i=0;i<p;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
ntt(p,A,B,C);
//puts("C:");for (int i=0;i<p;i++) printf("%d ",C[i]);puts("");
}
}NTT;
判断两球相交部分体积
typedef struct point {
double x, y, z;
point() {}
point(double a, double b, double c) {
x = a;
y = b;
z = c;
}
point operator -(const point& b)const {
return point(x - b.x, y - b.y, z - b.z);
}
point operator +(const point& b)const {
return point(x + b.x, y + b.y, z + b.z);
}
point operator *(const double& k)const {
return point(x * k, y * k, z * k);
}
point operator /(const double& k)const {
return point(x / k, y / k, z / k);
}
double operator *(const point& b)const {
return x * b.x + y * b.y + z * b.z;
}
}point;
double dist(point p1, point p2) {
return sqrt((p1 - p2) * (p1 - p2));
}
typedef struct sphere {
double r;
point centre;
}sphere;
double SphereInterVS(sphere a, sphere b) {
double d = dist(a.centre, b.centre);
if (d + a.r <= b.r) {
return (4.0 / 3.0) * PI * a.r * a.r * a.r;
}
if (d + b.r <= a.r) {
return (4.0 / 3.0) * PI * b.r * b.r * b.r;
}
double t = (d * d + a.r * a.r - b.r * b.r) / (2.0 * d);//
double h = sqrt((a.r * a.r) - (t * t)) * 2;
double angle_a = 2 * acos((a.r * a.r + d * d - b.r * b.r) / (2.0 * a.r * d));
double angle_b = 2 * acos((b.r * b.r + d * d - a.r * a.r) / (2.0 * b.r * d));
double l1 = ((a.r * a.r - b.r * b.r) / d + d) / 2;
double l2 = d - l1;
double x1 = a.r - l1, x2 = b.r - l2;
double v1 = PI * x1 * x1 * (a.r - x1 / 3);
double v2 = PI * x2 * x2 * (b.r - x2 / 3);
double v = v1 + v2;
return v;
}
求数组中子数组起码k个最大平均值
double find(double p[], int k,int n) {
double l = 600000;
double r = 0;
for (int i = 1; i <= n; i++) {
l = min(l, p[i]);
r = max(r, p[i]);
}
while (r - l > 1e-7) {
double mid = (r + l) / 2;
double suma[N] = {0};
for (int i = 1; i <= n; i++) {
suma[i] = suma[i-1] + p[i] - mid;
}
double premin = 0;
double summax = 0;
for (int i = k; i <= n; i++) {
summax = max(summax, suma[i] - premin);
premin = min(premin, suma[i - k + 1]);
}
if (summax > 0)
l = mid;
else r = mid;
}
return l;
}
求逆序对数
归并排序求逆序对数
int merge_count(int a[], int left, int mid, int right)
{
int *b = new int[right - left + 1];
int P1 = left;
int P2 = mid + 1;
int i = 0;
int S3 = 0;
while (P1 <= mid && P2 <= right)
{
if (a[P1] <= a[P2]){
b[i++] = a[P1++];
}
else{
b[i++] = a[P2++];
S3 += (mid - P1) + 1;
}
}
while (P1 <= mid){
b[i++] = a[P1++];
}
while (P2 <= right){
b[i++] = a[P2++];
}
for (int i = 0; i < right - left + 1; ++i){
a[i + left] = b[i];
}
delete[] b;
return S3;
}
int count_inver(int a[], int left, int right)
{
if (left >= right)
return 0;
int mid = (left + right) / 2;
int S1 = count_inver(a, left, mid);
int S2 = count_inver(a, mid + 1, right);
int S3 = merge_count(a, left, mid, right);
return (S1 + S2 + S3);
}
计算几何
struct Point
{
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
};
typedef Point Vector;
Vector operator+(Vector a, Vector b) { return Vector(a.x + b.x, a.y + b.y); }
Vector operator-(Vector a, Vector b) { return Vector(a.x - b.x, a.y - b.y); }
Vector operator*(Vector a, double p) { return Vector(a.x * p, a.y * p); }
Vector operator/(Vector a, double p) { return Vector(a.x / p, a.y / p); }
int dcmp(double x)
{
if (fabs(x) <= eps)
return 0;
else if (x > 0)
return 1;
return -1;
}
bool operator==(const Point &a, const Point &b) { return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0; }
double Dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
double Length(Vector a) { return sqrt(Dot(a, a)); }
double Angle(Vector a, Vector b) { return acos(Dot(a, b) / Length(a) / Length(b)); }
double Cross(Vector a, Vector b)
{
return a.x * b.y - a.y * b.x;
}
Vector Rotate(Vector a, double rad) { return Vector(a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad)); }
double Distance(Point a, Point b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
double Area(Point a, Point b, Point c) { return fabs(Cross(b - a, c - a) / 2); }
bool Intersect(Point A, Point B, Point C, Point D)
{
double t1 = Cross(C - A, D - A) * Cross(C - B, D - B);
double t2 = Cross(A - C, B - C) * Cross(A - D, B - D);
return dcmp(t1) < 0 && dcmp(t2) < 0;
}
bool StrictIntersect(Point A, Point B, Point C, Point D)
{
return dcmp(max(A.x, B.x) - min(C.x, D.x)) >= 0 && dcmp(max(C.x, D.x) - min(A.x, B.x)) >= 0 && dcmp(max(A.y, B.y) - min(C.y, D.y)) >= 0 && dcmp(max(C.y, D.y) - min(A.y, B.y)) >= 0 && dcmp(Cross(C - A, D - A) * Cross(C - B, D - B)) <= 0 && dcmp(Cross(A - C, B - C) * Cross(A - D, B - D)) <= 0;
}
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w)
{
Vector u = P - Q;
double t = Cross(w, u) / Cross(v, w);
return P + v * t;
}
凸包
#include <bits/stdc++.h>
using namespace std;
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef long long ll;
const int maxn = 2e5 + 50;
struct point
{
double x, y;
} p[maxn];
inline point del(point a, point b) { return (point){(b.x - a.x), (b.y - a.y)}; }
inline double dis(point a, point b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
inline double Xmul(point a, point b) { return a.x * b.y - b.x * a.y; }
inline bool operator<(const point &a, const point &b)
{
if (a.x == b.x)
return a.y < b.y;
return a.x < b.x;
}
int n, s[maxn];
void run()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> p[i].x >> p[i].y;
sort(p + 1, p + 1 + n);
double ans = 0;
int cnt = 0;
s[++cnt] = 1, s[++cnt] = 2;
for (int i = 3; i <= n; ++i)
{
point u = del(p[s[cnt - 1]], p[s[cnt]]);
point v = del(p[s[cnt]], p[i]);
while (Xmul(u, v) < 0.0)
{
if (cnt == 1)
break;
cnt--;
u = del(p[s[cnt - 1]], p[s[cnt]]), v = del(p[s[cnt]], p[i]);
}
s[++cnt] = i;
}
int tmp = cnt;
s[++cnt] = n, s[++cnt] = n - 1;
for (int i = n - 2; i >= 1; --i)
{
point u = del(p[s[cnt - 1]], p[s[cnt]]);
point v = del(p[s[cnt]], p[i]);
while (Xmul(u, v) < 0.0)
{
if (cnt == 1)
break;
cnt--;
u = del(p[s[cnt - 1]], p[s[cnt]]), v = del(p[s[cnt]], p[i]);
}
s[++cnt] = i;
}
for (int i = 1; i <= cnt; ++i)
cout << p[s[i]].x << ' ' << p[s[i]].y << "\n";
for (int i = 1; i <= cnt - 1; ++i)
ans += dis(p[s[i]], p[s[i + 1]]);
}
signed main()
{
FAST;
run();
return 0;
}
矩阵乘
struct Matrix
{
int mat[2][2];
int x, y;
Matrix(int a = 2, int b = 2)
{
x = a, y = b;
memset(mat, 0, sizeof(mat));
}
Matrix operator*(Matrix a)
{
Matrix res(x, a.y);
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
for (int k = 0; k < y; k++)
res.mat[i][j] = (res.mat[i][j] + mat[i][k] * a.mat[k][j]);
}
return res;
}
};
高斯消元
const int maxn = 1e3 + 10;
double mat[maxn][maxn];
double ans[maxn];
int n;
// false代表无解,true代表有解,解在ans[1]...ans[n]中
bool gauss()
{
for (int i = 1; i <= n; i++)
{
int maxrow = i;
for (int row = i + 1; row <= n; row++)
{
if (abs(mat[row][i]) > abs(mat[maxrow][i]))
maxrow = row;
}
if (maxrow != i)
swap(mat[i], mat[maxrow]);
if (mat[i][i] == 0)
return false;
for (int row = i + 1; row <= n; row++)
{
double k = mat[row][i] / mat[i][i];
for (int j = i; j <= n + 1; j++)
mat[row][j] -= k * mat[i][j];
}
}
for (int i = n; i >= 1; i--)
{
ans[i] = mat[i][n + 1] / mat[i][i];
for (int row = n - 1; row >= 1; row--)
mat[row][n + 1] -= mat[row][i] * ans[i], mat[row][i] = 0;
}
return true;
}