2024.1.17做题纪要
lct 模板
没啥好说的,直接上
罗生门
#include <bits/stdc++.h>
const int SIZE = 3e5 + 9;
class link_cut_tree {
#define lson (child[x][0])
#define rson (child[x][1])
public:
int child[SIZE][2], fat[SIZE];
long long path[SIZE], value[SIZE];
bool reverse[SIZE];
void splay(int x) {
int y, z;
update(x);
while (!is_root(x)) {
y = fat[x];
if (!is_root(y)) {
if (direction(x) == direction(y))
rotate(y);
else
rotate(x);
}
rotate(x);
}
pushup(x);
}
void pushup(int x) {
path[x] = path[lson] ^ path[rson] ^ value[x];
}
private:
bool is_root(int x) {
return (child[fat[x]][0] != x && child[fat[x]][1] != x);
}
void turn(int x) {
std::swap(lson, rson);
reverse[x] ^= 1;
}
bool direction(int x) {
return (child[fat[x]][1] == x);
}
void pushdown(int x) {
if (reverse[x]) {
if (lson)
turn(lson);
if (rson)
turn(rson);
reverse[x] = 0;
}
}
void rotate(int x) {
int y = fat[x], z = fat[y], chk = direction(x);
if (!is_root(y))
child[z][child[z][1] == y] = x;
if (child[x][!chk])
fat[child[x][!chk]] = y;
child[y][chk] = child[x][!chk];
child[x][!chk] = y;
fat[y] = x;
fat[x] = z;
pushup(y);
}
void update(int x) {
if (!is_root(x))
update(fat[x]);
pushdown(x);
}
void access(int x) {
for (int y = 0; x; y = x, x = fat[x]) {
splay(x);
child[x][1] = y;
pushup(x);
}
}
void make_root(int x) {
access(x);
splay(x);
turn(x);
}
int find_root(int x) {
access(x);
splay(x);
while (lson) {
pushdown(x);
x = lson;
}
splay(x);
return x;
}
public:
void split(int x, int y) {
make_root(x);
access(y);
splay(y);
}
void link(int x, int y) {
make_root(x);
if (find_root(y) != x)
fat[x] = y;
}
void cut(int x, int y) {
make_root(x);
if (find_root(y) == x && fat[y] == x && !child[y][0]) {
fat[y] = child[x][1] = 0;
pushup(x);
}
}
#undef lson
#undef rson
}tree;
int N, M;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> N >> M;
for (int i = 1; i <= N; ++ i)
std::cin >> tree.value[i];
while (M --) {
int opt, x, y;
std::cin >> opt >> x >> y;
if (opt == 0) {
tree.split(x, y);
std::cout << tree.path[y] << '\n';
}
else if (opt == 1) {
tree.link(x, y);
}
else if (opt == 2) {
tree.cut(x, y);
}
else {
tree.splay(x);
tree.value[x] = y;
tree.pushup(x);
}
}
return 0;
}
[ARC112F] Die Siedler
妙妙题,感觉根本想不出来。
根号分治,还有同余最短路。
这个是真不会将,也太麻烦了。
我用什么把你留住
#include <bits/stdc++.h>
typedef long long ll;
ll N, M, P, d;
ll a[20], f[20], dis[2000000];
ll get_sum() {
ll result = 0;
for (int i = 1; i <= N; ++ i)
result += a[i] * f[i - 1];
return result;
}
ll query(ll rest) {
ll result = 0;
for (int i = 1; i <= N; ++ i) {
result += rest % (2 * i);
rest = rest / (2 * i);
}
return result;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> N >> M;
f[0] = 1;
for (int i = 1; i <= N; ++ i)
f[i] = f[i - 1] * 2 * i;
for (int i = 1; i <= N; ++ i)
std::cin >> a[i];
P = get_sum();
d = f[N] - 1;
for (int i = 1; i <= M; ++ i) {
for (int j = 1; j <= N; ++ j)
std::cin >> a[j];
ll temp = get_sum();
d = std::__gcd(d, temp);
}
if (P == 0) {
std::cout << 0 << '\n';
return 0;
}
if (d <= std::sqrt(f[N])) {
std::queue<int> queue;
memset(dis, -1, sizeof(dis));
for (int i = 0; i < N; ++ i) {
queue.emplace(f[i] % d);
dis[f[i] % d] = 1;
}
while (queue.size()) {
int now = queue.front();
queue.pop();
for (int i = 0; i < N; ++ i) {
ll to = (now + f[i]) % d;
if (dis[to] == -1) {
dis[to] = dis[now] + 1;
queue.emplace(to);
}
}
}
std::cout << std::min(query(P), dis[P % d]) << '\n';
}
else {
ll answer = query(P);
for (ll i = (P % d ? P % d : d); i < f[N]; i += d)
answer = std::min(answer, query(i));
std::cout << answer << '\n';
}
return 0;
}
ALO
简单题,读明白题了就很板子。
我们将每个数从大到小排序。并从前向后遍历。
同时维护一个 \(set\),每次将当前的数插入后,查询在本位置左右两端最靠近本位置 \(i\) 的两个位置 \(l_1,l_2\) 或 \(r_1,r_2\) (\(l_1 \leq l_2,r_1 \leq r_2\))就行。
因为我们在插入当前数的时候,把比当前数大的数都在前面加了,所以合法区间就是 \(l_1 + 1\) 到 \(i - 1\) 和 \(i + 1\) 到 \(r_2 - 1\)。
清空
#include <bits/stdc++.h>
class Trie {
public:
int root[51000], tot;
int child[51000 * 35][2], max[51000 * 35];
void insert(int rank, int number) {
root[rank] = ++ tot;
int now = root[rank];
max[now] = rank;
int last = root[rank - 1];
for (int i = 30; i >= 0; -- i) {
child[now][0] = child[last][0];
child[now][1] = child[last][1];
int ch = (number >> i) & 1;
child[now][ch] = ++ tot;
now = child[now][ch];
last = child[last][ch];
max[now] = rank;
}
}
int ask(int l, int r, int number) {
if (l > r)
return number;
int result = 0;
int now = root[r];
for (int i = 30; i >= 0; -- i) {
int ch = (number >> i) & 1;
int to = child[now][!ch];
if (max[to] < l || !to) {
now = child[now][ch];
result += ((1 & ch) << i);
}
else {
now = to;
result += ((1 & (!ch)) << i);
}
}
return result;
}
}trie;
int N, answer;
std::pair<int, int> a[51000];
std::multiset<int> set;
bool visit[51000];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> N;
for (int i = 1; i <= N; ++ i) {
std::cin >> a[i].first;
trie.insert(i, a[i].first);
a[i].first *= -1;
a[i].second = i;
}
std::sort(a + 1, a + 1 + N);
set.emplace(1);
set.emplace(N);
set.emplace(a[1].second);
for (int i = 2; i <= N; ++ i) {
a[i].first *= -1;
set.emplace(a[i].second);
std::multiset<int>::iterator iter = set.find(a[i].second);
int left = *std::prev(iter);
int right = *std::next(iter);
if (left != 1)
left = *std::prev(iter, 2) + 1;
if (right != N)
right = *std::next(iter, 2) - 1;
int temp1 = trie.ask(left, a[i].second - 1, a[i].first);
int temp2 = trie.ask(a[i].second + 1, right, a[i].first);
answer = std::max({answer, temp1 ^ a[i].first, temp2 ^ a[i].first});
}
std::cout << answer << '\n';
return 0;
}
[bzoj3956] Count
有点水平。
首先对于操作一是简单的不用管,重点去看操作二。
我们可以用上一个题:ALO 的方法处理出来每个数最靠近的左右两端的比它大的位置,然后插入可持久化线段树就行了。
counting stars
#include <bits/stdc++.h>
const int SIZE = 3e5 + 100;
class segment_tree {
#define lid (lson[id])
#define rid (rson[id])
public:
int tot;
std::pair<int, int> root[SIZE];
int sum[SIZE * 70], lson[SIZE * 70], rson[SIZE * 70];
private:
int make(int id) {
++ tot;
sum[tot] = sum[id];
lson[tot] = lson[id];
rson[tot] = rson[id];
return tot;
}
void pushup(int id) {
sum[id] = sum[lid] + sum[rid];
}
public:
int update(int id, int l, int r, int pos) {
id = make(id);
if (l == r) {
sum[id] ++;
return id;
}
int mid = (l + r) >> 1;
if (pos <= mid)
lid = update(lid, l, mid, pos);
else
rid = update(rid, mid + 1, r, pos);
pushup(id);
return id;
}
int query(int lRoot, int rRoot, int l, int r, int askL, int askR) {
if (sum[rRoot] == sum[lRoot])
return 0;
if (askL <= l && r <= askR)
return sum[rRoot] - sum[lRoot];
int mid = (l + r) >> 1, result = 0;
if (askL <= mid)
result += query(lson[lRoot], lson[rRoot], l, mid, askL, askR);
if (mid + 1 <= askR)
result += query(rson[lRoot], rson[rRoot], mid + 1, r, askL, askR);
return result;
}
#undef lid
#undef rid
}tree;
int N, M, type;
int num[310000], L[310000], R[310000];
std::pair<int, int> a[310000];
std::multiset<int> set;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> N >> M >> type;
for (int i = 1; i <= N; ++ i) {
std::cin >> num[i];
a[i].first = -1 * num[i];
a[i].second = i;
}
std::sort(a + 1, a + 1 + N);
for (int j = 1, to; j <= N; j = to) {
to = j;
set.emplace(a[to].second);
while (to + 1 <= N && a[to].first == a[to + 1].first) {
set.emplace(a[to + 1].second);
to ++;
}
for (int i = j; i <= to; ++ i) {
std::multiset<int>::iterator iter = set.find(a[i].second);
if (iter != set.begin())
L[a[i].second] = *std::prev(iter);
if (iter != std::prev(set.end()))
R[a[i].second] = *std::next(iter);
}
to ++;
}
for (int i = 1; i <= N; ++ i) {
int last = std::max(tree.root[i - 1].first, tree.root[i - 1].second);
tree.root[i] = std::make_pair(last, last);
if (L[i] && L[i] != i - 1)
last = tree.root[i].first = tree.update(last, 1, N, L[i]);
tree.root[i].second = last;
if (R[i] && R[i] != i + 1 && num[R[i]] != num[i])
tree.root[i].second = tree.update(last, 1, N, R[i]);
}
int answer = 0;
for (int i = 1, l, r, u, v; i <= M; ++ i) {
std::cin >> u >> v;
if (type == 0) {
l = u;
r = v;
}
else {
u = (u + answer - 1) % N + 1;
v = (v + answer - 1) % N + 1;
l = std::min(u, v);
r = std::max(u, v);
}
int lRoot = std::max(tree.root[l - 1].first, tree.root[l - 1].second);
int rRoot = std::max(tree.root[r].first, tree.root[r].second);
answer = tree.query(lRoot, rRoot, 1, N, l, r) + (r - l);
std::cout << answer << '\n';
}
return 0;
}