# JOISC 2020 做题记录

## Day1 T1 Building 4

### 题意

$$n \le 5 \times 10 ^ 5$$

### 代码

#include <algorithm>
#include <cstdio>
#include <cstring>

const int MaxN = 1000000;

int N;
int A[MaxN + 5], B[MaxN + 5];
int L[MaxN + 5][2], R[MaxN + 5][2];
bool F[MaxN + 5][2];
int Ans[MaxN + 5];

void init() {
scanf("%d", &N);
N <<= 1;
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
for (int i = 1; i <= N; ++i) scanf("%d", &B[i]);
}

void solve() {
L[0][0] = L[0][1] = R[0][0] = R[0][1] = 0;
F[0][0] = F[0][1] = true;
for (int i = 1; i <= N; ++i) {
L[i][0] = N + 1, R[i][0] = -1;
L[i][1] = N + 1, R[i][1] = -1;
if (A[i] >= A[i - 1] && F[i - 1][0] == true) {
L[i][0] = std::min(L[i][0], L[i - 1][0] + 1);
R[i][0] = std::max(R[i][0], R[i - 1][0] + 1);
F[i][0] = true;
}
if (A[i] >= B[i - 1] && F[i - 1][1] == true) {
L[i][0] = std::min(L[i][0], L[i - 1][1] + 1);
R[i][0] = std::max(R[i][0], R[i - 1][1] + 1);
F[i][0] = true;
}
if (B[i] >= A[i - 1] && F[i - 1][0] == true) {
L[i][1] = std::min(L[i][1], L[i - 1][0]);
R[i][1] = std::max(R[i][1], R[i - 1][0]);
F[i][1] = true;
}
if (B[i] >= B[i - 1] && F[i - 1][1] == true) {
L[i][1] = std::min(L[i][1], L[i - 1][1]);
R[i][1] = std::max(R[i][1], R[i - 1][1]);
F[i][1] = true;
}
}
int ok = -1;
if (F[N][0] == true && L[N][0] <= N / 2 && N / 2 <= R[N][0]) ok = 0;
if (F[N][1] == true && L[N][1] <= N / 2 && N / 2 <= R[N][1]) ok = 1;
if (ok == -1) puts("-1");
else {
int last = N / 2;
for (int i = N; i >= 1; --i) {
Ans[i] = ok;
if (ok == 0) {
last--;
if (F[i - 1][0] == true && A[i - 1] <= A[i] && L[i - 1][0] <= last && last <= R[i - 1][0]) ok = 0;
else ok = 1;
} else {
if (F[i - 1][0] == true && A[i - 1] <= B[i] && L[i - 1][0] <= last && last <= R[i - 1][0]) ok = 0;
else ok = 1;
}
}
for (int i = 1; i <= N; ++i)
putchar("AB"[Ans[i]]);
putchar('\n');
}
}

int main() {
init();
solve();
return 0;
}


## Day1 T2 Hamburg Steak

### 题意

$$n \le 2 \times 10 ^ 5$$$$k \le 4$$

## Day1 T3 Sweeping

### 题意

$$n \times n$$ 的平面上，初始有 $$m$$ 个点，进行 $$q$$ 次操作。操作有以下四种：

• 询问一个点的位置。
• 给出参数 $$l$$，把所有 $$(x, y)$$ 满足 $$x \lt n - l, y \le l$$ 的点移到 $$(n - l, y)$$
• 给出参数 $$l$$，把所有 $$(x, y)$$ 满足 $$x \le l, y \lt n - l$$ 的点移到 $$(x, n - l)$$
• 加入一个点。

$$n \le 10 ^ 9$$$$m \le 5 \times 10 ^ 5$$$$q \le 10 ^ 6$$

## Day2 T1 Chameleon’s Love

### 题意

$$2n$$ 只变色龙，$$n$$ 只为雄性，$$n$$ 只为雌性。每只变色龙有一个初始颜色 $$c_i$$，满足对于雄性和雌性内部来说，$$c_i$$ 都是一个 $$1 \sim n$$ 的排列。此外，每只变色龙还有喜欢的对象 $$l_i$$

$$n \le 500$$

## Day2 T2 Making Friends on Joitter is Fun

### 题意

$$n \le 10 ^ 5$$$$m \le 3 \times 10 ^ 5$$

## Day2 T3 Ruins 3

### 题意

$$2n$$ 座石柱，初始时对于每个 $$x ~ (1 \le x \le n)$$，都有两座石柱高度为 $$x$$，接着发生了 $$n$$ 次地震，第 $$i$$ 次地震会使得所有的高度不为 $$0$$ 的石柱 $$j$$，设其原本高度为 $$h_j$$，若满足存在一个 $$k$$ 使得 $$h_j = h_k$$，石柱 $$j$$ 的高度就会减一。

$$n \le 600$$

## Day3 T1 Constellation 3

### 题意

$$n, m \le 2 \times 10 ^ 5$$

### 题解

$$u$$ 上做合并的时候，一种是不做特别操作，$$f_u = f_{lson(u)} + f_{rson(u)}$$

### 代码

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>

const int MaxN = 200000, MaxM = 200000;
const int MaxV = 400000, MaxLog = 19;

struct edge_t {
int u, v, w;
edge_t(int _u = 0, int _v = 0, int _w = 0) { u = _u, v = _v, w = _w; }
inline friend bool operator<(const edge_t &a, const edge_t &b) { return a.w < b.w; }
};

struct star_t {
int x, y, c;
star_t(int _x = 0, int _y = 0, int _c = 0) { x = _x, y = _y, c = _c; }
};

int N, M, V;
long long Sum;
int Height[MaxN + 5];
star_t A[MaxM + 5];
int Par[MaxV + 5], Fa[MaxLog + 1][MaxV + 5], Dep[MaxV + 5], Weight[MaxV + 5], Lson[MaxV + 5], Rson[MaxV + 5];
int Siz[MaxV + 5], Wson[MaxV + 5], Top[MaxV + 5];
std::vector<int> Vec[MaxV + 5];
long long F[MaxV + 5], Suf[MaxV + 5];

void init() {
scanf("%d", &N);
for (int i = 1; i <= N; ++i) scanf("%d", &Height[i]);
N++; Height[N] = N;
scanf("%d", &M);
for (int i = 1; i <= M; ++i) {
scanf("%d %d %d", &A[i].x, &A[i].y, &A[i].c);
Sum += A[i].c;
}
}

int find(int x) { return x == Par[x] ? x : Par[x] = find(Par[x]); }

void dfs(int u) {
Siz[u] = 1;
if (u <= N) return;
Dep[Lson[u]] = Dep[u] + 1;
Fa[0][Lson[u]] = u;
for (int i = 1; (1 << i) <= Dep[Lson[u]]; ++i)
Fa[i][Lson[u]] = Fa[i - 1][Fa[i - 1][Lson[u]]];
Dep[Rson[u]] = Dep[u] + 1;
Fa[0][Rson[u]] = u;
for (int i = 1; (1 << i) <= Dep[Rson[u]]; ++i)
Fa[i][Rson[u]] = Fa[i - 1][Fa[i - 1][Rson[u]]];
dfs(Lson[u]), dfs(Rson[u]);
Siz[u] += Siz[Lson[u]] + Siz[Rson[u]];
if (Siz[Lson[u]] > Siz[Rson[u]]) Wson[u] = Lson[u];
else Wson[u] = Rson[u];
}

void dfs(int u, int chain) {
Top[u] = chain;
if (u <= N) return;
dfs(Wson[u], chain);
dfs(Wson[u] == Lson[u] ? Rson[u] : Lson[u], Wson[u] == Lson[u] ? Rson[u] : Lson[u]);
}

inline int binSearch(int u, int val) {
for (int i = MaxLog; i >= 0; --i) {
if (Fa[i][u] == 0) continue;
if (Weight[Fa[i][u]] < val) u = Fa[i][u];
}
return u;
}

inline long long queryPath(int u, int f) {
long long res = 0;
while (Top[u] != Top[f]) {
res += Suf[Top[u]] - Suf[u];
u = Fa[0][Top[u]];
res += F[Wson[u]];
}
res += Suf[f] - Suf[u];
return res;
}

void bfs() {
static int que[MaxV + 5], ind[MaxV + 5];
int head = 1, tail = 0;
for (int i = N + 1; i <= V; ++i) ind[i] = 2;
for (int i = 1; i <= N; ++i) que[++tail] = i;
if (u > N) {
F[u] = F[Lson[u]] + F[Rson[u]];
Suf[u] += Suf[Wson[u]];
}
for (int id : Vec[u]) {
int x = A[id].x, c = A[id].c;
F[u] = std::max(F[u], queryPath(x, u) + c);
}
if (u != V && Wson[Fa[0][u]] != u) Suf[Fa[0][u]] += F[u];
ind[Fa[0][u]]--;
if (ind[Fa[0][u]] == 0) que[++tail] = Fa[0][u];
}
}

void solve() {
static edge_t e[MaxN + 5];
for (int i = 1; i < N; ++i) e[i] = edge_t(i, i + 1, std::max(Height[i], Height[i + 1]));
std::sort(e + 1, e + N);
for (int i = 1; i <= N; ++i) Par[i] = i;
V = N;
for (int i = 1; i < N; ++i) {
int u = e[i].u, v = e[i].v, w = e[i].w;
int p = find(u), q = find(v);
V++;
Par[p] = Par[q] = Par[V] = V;
Weight[V] = w;
Lson[V] = p, Rson[V] = q;
}
dfs(V), dfs(V, V);
for (int i = 1; i <= M; ++i) {
int f = binSearch(A[i].x, A[i].y);
Vec[f].push_back(i);
}
bfs();
printf("%lld\n", Sum - F[V]);
}

int main() {
init();
solve();
return 0;
}


## Day3 T2 Harvest

### 题意

$$Q$$ 次询问，每次询问给出两个数 $$V_i, T_i$$，询问对于第 $$V_i$$ 号员工，进行 $$T_i$$ 时间后，采了多少苹果。

$$L, C \le 10 ^ 9$$$$N, M \le 2 \times 10 ^ 5$$$$T_i \le 10 ^ {18}$$

## Day3 T3 Stray Cat

### 题意

Catherine 获取的信息是，对于当前的点，除了走来的那条边以外，每种标记对于的其它边的数量。她可以选择一个颜色走，也可以沿着刚来的那条边往回走。

$$n, m \le 20\ 000$$

• $$a = 3, b = 0$$
• $$a = 2, m = n - 1, b = 6$$

### 题解

#### 第一类 $$a = 3, b = 0$$

$$0$$ 号点开始跑原图的最短路，建出最短路树。根据三角形不等式，对于原来的每条边，要么连接相邻的两层，要么连接同一层内的两点。我们令连接相邻两层的边颜色按照深度依次为 $$0, 1, 2, 0, 1, 2, \ldots$$，连接同一层内的边颜色为该层连向下一层的边的颜色以保证 Catherine 永远不会走。