校内训练 2019-09-15

吐槽

这一天困得不行,然后看题的时候想了一会儿 T1 的算法,写了写,然后听到旁边的学弟们说“T1 不用 40 行就能写完”,然后我就望着我眼前的 120+ 行的代码(其实 120 行不算很长,但是比 40 行差远了把)愣了半天。最后因为 T1 不会写暴力也没有对拍,所以交上去的时候还是很悬的。

T2 想了一个 \(O(nk\log n)\),不好写,不敢写,要是没有被卡就很好,但是如果被卡掉了。。。就和 30 行的暴力一样的分。

T3 基本上没怎么看,最后赶了一个可以拿到 35pts 的暴力,结果获得了 0pts 的好成绩。

然后,这场比赛的每一道题的数据比随机数据还要弱。订正的时候,我 T2 写了一堆错误,结果一共 10 个点就错了 1 个点,然后随机数据拍一个点就能拍出问题。

这个 T3 的 \(O(n^2)\) 的暴力可以直接跑过去(如果我考试的时候没有把暴力写挂那么这道题可以直接 A 掉)。

最后再吐槽一句,这个比赛的 T2 T3 正解都非常难调。可以通过代码中被我注释掉的调试语句的数量看出。

T1. 精心安排

题目传送门

内网网址:http://192.168.21.187/contest/28/problem/1 = http://192.168.21.187/problem/1301

外网网址:http://47.100.137.146/contest/28/problem/1 = http://47.100.137.146/problem/1301

(需要我校 OJ 的权限)

题解

要求相当于整棵树以某种顺序遍历的 dfs 序的前 \(k\) 的最小值最大。

显然二分一个 \(mid\),然后前 \(k\) 个都应该 \(\geq mid\)。对于完成度 \(< mid\) 的点,我们称之为“坏点”。

先不考虑选哪个为根的情况,我们钦定 \(1\) 为根。然后把所有的子树分为两类,第一类子树中没有坏点,第二类子树中存在坏点。对于第二类子树,我们维护一个 \(f[x]\) 表示在 \(x\) 的子树中,在不经过坏点的情况下,最多可以走过多少点。

显然对于一棵树,我们应该先走第一类子树。最后,取第二类子树中的 \(f\) 值最大的走。这样显然是最优的。\(f\) 值也可以这样的方式求出。

但是根不一定为 \(1\)。所以我们只需要对之进行换根 dp 就可以了。

下面是代码,时间复杂度为 \(O(n\log s_i)\)

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

const int N = 200000 + 7;

int n, m, mxs, mns = N, ggk;
int a[N], siz[N], si[N], s[N], bd[N], vt[N];
std::vector<int> v[N];

struct Edge { int to, ne; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }

inline void dfs1(int x, int fa = 0) {
	siz[x] = si[x] = 1, s[x] = 0;
	int sp = 0;
	for fec(i, x, y) if (y != fa) {
		dfs1(y, x);
		siz[x] += siz[y];
		if (si[y] + s[y] == siz[y]) si[x] += si[y] + s[y];
		else smax(s[x], si[y] + s[y]);
	}
	vt[0] = 0;
	for fec(i, x, y) if (y != fa) vt[++vt[0]] = y;
	v[x].resize(vt[0] + 1);
	v[x][vt[0]] = 0;
	for (int i = vt[0]; i; --i) {
		int y = vt[i];
		if (si[y] + s[y] < siz[y]) smax(sp, si[y] + s[y]);
		v[x][i - 1] = sp;
	}
	if (bd[x]) si[x] = s[x] = 0;
//	dbg("x = %d, si[x] = %d, s[x] = %d\n", x, si[x], s[x]);
}

inline void dfs2(int x, int fa = 0, int add = 0, int addt = 0) {
//	dbg("x = %d, fa = %d, add = %d, addt = %d, %d %d, %d\n", x, fa, add, addt, si[x], s[x], ggk);
	if (!bd[x]) {
		if (addt) smax(ggk, si[x] + s[x] + add);
		else smax(ggk, si[x] + std::max(s[x], add));
	}
	int prev = 0, id = 0;
	for fec(i, x, y) if (y != fa) {
		int add2 = 0, addt2 = 0;
		++id;
		if (!bd[x]) {
			if (!addt) {
				if (si[y] + s[y] < siz[y]) add2 = si[x] + std::max(std::max(prev, v[x][id]), add);
				else add2 = si[x] - (si[y] + s[y]) + std::max(std::max(prev, v[x][id]), add);
			} else {
				if (si[y] + s[y] < siz[y]) add2 = add + si[x] + std::max(prev, v[x][id]);
				else add2 = add + si[x] - (si[y] + s[y]) + std::max(prev, v[x][id]);
			}
		}
		addt2 = (add2 == n - siz[y]);
		dfs2(y, x, add2, addt2);
		if (si[y] + s[y] < siz[y]) smax(prev, si[y] + s[y]);
	}
}

inline bool check(int mid) {
	for (int i = 1; i <= n; ++i) bd[i] = a[i] < mid;
	ggk = 0;
	dfs1(1);
	dfs2(1);
//	dbg("mid = %d, ggk = %d\n", mid, ggk);
	return ggk >= m;
}

inline void work() {
	int l = mns, r = mxs;
	while (l < r) {
		int mid = (l + r + 1) >> 1;
		if (check(mid)) l = mid;
		else r = mid - 1;
	}
	printf("%d\n", l);
}

inline void init() {
	read(n), read(m);
	for (int i = 1; i <= n; ++i) read(a[i]), smin(mns, a[i]), smax(mxs, a[i]);
	int x, y;
	for (int i = 1; i < n; ++i) read(x), read(y), adde(x, y);
}

int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#else
	File(arrange);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}

T2. 创造 aba

题目传送门

内网网址:http://192.168.21.187/contest/28/problem/2 = http://192.168.21.187/problem/1302

外网网址:http://47.100.137.146/contest/28/problem/2 = http://47.100.137.146/problem/1302

(需要我校 OJ 的权限)

题解

有一个非常显然的 \(O(k\sum |S_i|)\) 的做法。令 \(f[i][j]\) 表示前 \(i\) 个串中形成的长度为 \(j\) 的串的最小的字符串,直接背包转移就可以了。

\(b[i][j]\) 表示前 \(i\) 个串形成的长度为 \(j\) 的串,能否在接后面的串以后形成长度为 \(k\) 的串。

可以发现这样的一个性质:若 \(b[i][j] = 1\)\(b[i][k] = 1\),则 \(f[i][j]\) 一定为 \(f[i][k]\) 的前缀。否则,二者中至少有一个不会再有存在价值了。因此我们只需要维护一个长度最多为 \(k\) 的串 \(S\),以及它的哪些位是一个合法 \(f[i][j]\),记这个数组为 \(p\)

维护方法就是,对于即将要添加的第 \(i\) 个串,在 \(p\) 中每一个合法位置的后面,都尝试添加一遍,然后取所有的情况中字典序最小的。但是如果一个串是另一个串的前缀,一定要取最长的。至于怎么比较,可以使用很多方法,但是它们的本质都是要知道第 \(i\) 个串与之前的 \(S\) 的每一个后缀的 lcp。这个可以通过 exkmp 快速线性求出。

然后更新 \(p\) 数组。对于新串和旧串开始出现差异的地方后面的 \(p\) 肯定要全部舍弃。然后对于剩下的合法 \(p\),如果接上第 \(i\) 个串以后,仍然是新串的前缀,那么那个前缀的位置也是合法的 \(p\)

最后的答案就是最终的 \(S\)

下面是代码。总的时间复杂度为 \(O(nk+\sum|S_i|)\)

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

const int N = 3000 + 7;
const int M = 10000 + 7;
const int L = 1e6 + 7;

int n, m, ln;
std::bitset<M> b[N];
std::string ss[N];
char s[L], a[M];
int fa[L], ext[M], p[M];

inline void make_fail(char *s, int n) {
	fa[1] = n, fa[2] = 0;
	while (fa[2] < n - 1 && s[fa[2] + 1] == s[fa[2] + 2]) ++fa[2];
	int p = 2;
	for (int i = 3; i <= n; ++i) {
		fa[i] = std::min(fa[i - p + 1], std::max(0, p + fa[p] - i));
		while (i + fa[i] <= n && s[fa[i] + 1] == s[fa[i] + i]) ++fa[i];
		if (i + fa[i] > p + fa[p]) p = i;
	}
}
inline void exkmp(char *s, char *t, int n, int m) {
	for (ext[1] = 0; ext[1] < n && ext[1] < m && s[ext[1] + 1] == t[ext[1] + 1]; ) ++ext[1];
	int p = 1;
	for (int i = 2; i <= n; ++i) {
		ext[i] = std::min(fa[i - p + 1], std::max(0, p + ext[p] - i));
		while (i + ext[i] <= n && ext[i] + 1 <= m && s[i + ext[i]] == t[ext[i] + 1]) ++ext[i];
		if (i + ext[i] > p + ext[p]) p = i;
	}
//	for (int i = 1; i <= n; ++i) dbg("fa[%d] = %d\n", i, ext[i]);
}

inline int cmp(int p1, int p2, int n, int l) {
	int q1 = ext[p1 + 1], q2 = ext[p2 + 1];
//	dbg("p1 = %d, p2 = %d, q1 = %d, q2 = %d, n = %d, l = %d\n", p1, p2, q1, q2, n, l);
	if (q2 + 1 > l || (p2 + q2 + 1 <= n && a[p2 + q2 + 1] < s[q2 + 1])) return -1;
	if (p1 == -1) return 1;
	if (q1 == l && p1 + q1 <= p2 + q2) return 0;
	if (p1 + q1 < p2 + q2) return -1;
	else if (p2 + q2 < p1 + q1) return 1;
	int q3 = fa[p2 - p1 + 1];
//	dbg("q3 = %d\n", q3);
	if (p2 - p1 + q3 >= l) return 0;
	else return s[q3 + 1] < s[p2 - p1 + q3 + 1] ? 1 : -1;
}

inline void work() {
	p[0] = 1, b[n][m] = 1;
//	std::cerr << b[n].to_string().substr(M - m - 1, M - 1) << std::endl;
	for (int i = n - 1; i; --i) b[i] = b[i + 1] | (b[i + 1] >> ss[i + 1].size());//, std::cerr << b[i].to_string().substr(M - m - 1, M - 1) << std::endl;
	for (int i = 1; i <= n; ++i) {
		strcpy(s + 1, ss[i].c_str());
		int l = strlen(s + 1), mx = -1;
		make_fail(s, l);
		exkmp(a, s, ln, l);
//		dbg("l = %d, ln = %d\n", l, ln);
		for (int j = 0; j + l <= m && j <= ln; ++j)
			if (p[j] && b[i][j + l] && cmp(mx, j, ln, l) >= 0) mx = j;
//		dbg("**************** mx = %d\n", mx);
		if (~mx) {
			int gg = ext[mx + 1];
			for (int j = mx + gg + 1; j <= ln; ++j) p[j] = 0;
			for (int j = mx; ~j; --j) if (p[j] && b[i][j + l] && cmp(j, mx, ln, l) == 0) p[j + l] = 1;
			for (int i = mx + 1, j = 1; j <= l; ++j, ++i) a[i] = s[j];
			a[(ln = mx + l) + 1] = 0;
		} else if (ln >= l) for (int j = ln - l; ~j; --j) if (p[j] && b[i][j + l] && ext[j + 1] == l) p[j + l] = 1;//, dbg("***** j = %d\n", j);
//		dbg("When i = %d, a = %s, p = {", i, a + 1);
//		for (int i = 0; i <= ln; ++i) if (p[i]) dbg("%d, ", i);
//		dbg("}\n");
	}
	puts(a + 1);
}

inline void init() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cin >> n >> m;
	for (int i = 1; i <= n; ++i) std::cin >> ss[i];
}

int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#else
	File(aba);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}

T3. 穿越荒野

题目传送门

内网网址:http://192.168.21.187/contest/28/problem/3 = http://192.168.21.187/problem/1303

外网网址:http://47.100.137.146/contest/28/problem/3 = http://47.100.137.146/problem/1303

(需要我校 OJ 的权限)

题解

先只考虑单向,有一个显然的贪心的 \(O(n^2)\) 做法:一直向右走,走不了了就花钱。

考虑这个算法的本质相当于是令 \(p_i = p_{i-1}+a_{i-1}-d_{i-1}\),即从 \(1\)\(i\) 的总加油量减去总路径长。然后第一个 \(p_j < p_i(j>i)\)\(j\) 就是 \(i\) 后面第一次需要花钱的地方。以此类推。这个 \(j\) 可以使用单调栈求出。每一个 \(j\)\(i\) 形成了一个树的关系。进入一个子树,就要付出树根的权值减去父亲的权值的花费。

同理,在逆向走的时候,我们令 \(q_i = q_{i-1}+a_i-d_{i-1}\),那么对于 \(j>i\),从 \(j\)\(i\) 需要补交的费用就是 \(\max\limits_{k=i}^{j} q_{k} - q_j\)。但是因为之前正向走的时候我们已经修改过了 \(a\) 的一些值,所以这里也要修改。

\(calc(i, j)\) 表示从 \(i\) 正向到 \(j\) 需要的花费,于是最后问题变成了求最大的 \(j\),使得 \(calc(i, j) + \max\limits_{k=i}^{j} q_{k} - q_j \leq k\)。如果没有 \(\max\limits_{k=i}^{j} q_{k} - q_j\),可以直接在线段树上二分。

类似于 BZOJ2957楼房重建,我们可以令 \(val\) 表示当前区间的右子区间中,如果 \(\max\limits_{k=i}^{j} q_{k} - q_j\) 中的 \(k\) 只考虑当前区间(包括左子区间)时,\(calc(i, j) + \max\limits_{k=i}^{j} q_{k} - q_j\) 的最小值。

如何维护 \(val\):问题转化为给定一个前缀最大值 \(P\),只考虑当前区间内的 \(k\)\(calc(i, j) + \max\limits_{k=i}^{j} q_{k} - q_j\) 的最小值,设对于区间 \(o\),答案为 \(M(o,P)\)。设 \(lc\) 表示 \(o\) 的左子区间,\(rc\) 表示 \(o\) 的右子区间。

如果 \(P\) 小于等于左子区间的 \(q\) 最大值,那么 \(P\) 对于右子区间没有影响,直接返回 \(\max(M(lc), val_o)\)

否则,左子区间的 \(\max\limits_{k=i}^{j} q_{k}\) 一定确定为 \(P\),直接加上左子区间的 \(calc(i, j) - q_j\) 的最小值就可以了,然后递归右子区间并比较。

如何查询:如果 \(P\) 小于等于左子区间的 \(q\) 最大值,那么 \(P\) 对于右子区间没有影响。如果 \(val_o \leq k\) ,那么递归右子区间,否则递归左子区间。

否则,左子区间的 \(\max\limits_{k=i}^{j} q_{k}\) 一定确定为 \(P\),直接在左子区间二分。然后递归右子区间。

总的时间复杂度为 \(O(n\log n^2)\)

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

#define lc o << 1
#define rc o << 1 | 1

const int N = 1e5 + 7;
const ll INF = 1e17;

int n, m, tl;
int a[N], d[N], qq[N], nxt[N], ans[N];
ll p[N], q[N], ddl[N];

struct Edge { int to, ne; } g[N]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }

struct Node {
	ll maxq, mina, val, add;
} t[N << 2]; int nod;
inline void pushdown(int o, int L, int R) {
	if (!t[o].add) return;
	int M = (L + R) >> 1;
	t[lc].add += t[o].add, t[lc].maxq += t[o].add, t[lc].val += t[o].add;
	t[rc].add += t[o].add, t[rc].maxq += t[o].add, t[rc].val += t[o].add;
	t[o].add = 0;
}
inline ll qmin(int o, int L, int R, ll x) {
	if (L == R) return t[o].mina + std::max(x, t[o].maxq - ddl[L]);
	int M = (L + R) >> 1;
	pushdown(o, L, R);
	if (x <= t[lc].maxq) return std::min(qmin(lc, L, M, x), t[o].val);
	else return std::min(t[lc].mina + x, qmin(rc, M + 1, R, x));
}
inline void pushup(int o, int L, int R) {
	int M = (L + R) >> 1;
	t[o].maxq = std::max(t[lc].maxq, t[rc].maxq);
	t[o].mina = std::min(t[lc].mina, t[rc].mina);
	t[o].val = qmin(rc, M + 1, R, t[lc].maxq);
}
inline void build(int o, int L, int R) {
	if (L == R) {
		t[o].maxq = q[L], t[o].mina = -q[L];
		t[o].val = t[o].add = 0;
//		dbg("o = %d, L = %d, R = %d, t[o].maxq = %lld, t[o].mina = %lld, t[o].val = %lld, t[o].add = %lld\n", o, L, R, t[o].maxq, t[o].mina, t[o].val,t[o].add);
		return;
	}
	int M = (L + R) >> 1;
	build(lc, L, M), build(rc, M + 1, R);
	pushup(o, L, R);
//	dbg("o = %d, L = %d, R = %d, t[o].maxq = %lld, t[o].mina = %lld, t[o].val = %lld, t[o].add = %lld\n", o, L, R, t[o].maxq, t[o].mina, t[o].val,t[o].add);
}
inline void qadd(int o, int L, int R, int l, int r, ll k) {
	if (l > r) return;
//	dbg("qadd : o = %d, L = %d, R = %d, l = %d, r = %d, k = %lld\n", o, L, R, l, r, k);
	if (l <= L && R <= r) {
		t[o].add += k, t[o].maxq += k, t[o].val += k;
//		dbg("*\n");
		return;
	}
	int M = (L + R) >> 1;
	pushdown(o, L, R);
	if (l <= M) qadd(lc, L, M, l, r, k);
	if (r > M) qadd(rc, M + 1, R, l, r, k);
	pushup(o, L, R);
}
inline int qans2(int o, int L, int R, ll k) {
	if (t[o].mina + k > m) return 0;
	if (L == R) return t[o].mina + k <= m ? L : 0;
	pushdown(o, L, R);
	int M = (L + R) >> 1;
	if (t[rc].mina + k <= m) return qans2(rc, M + 1, R, k);
	else return qans2(lc, L, M, k);
}
inline int qans(int o, int L, int R, ll k) {
//	dbg("qans : o = %d, L = %d, R = %d, k = %lld, mima = %lld, maxq = %lld, t[o].add = %lld, t[lc].maxq = %lld, t[o].val = %lld\n", o, L, R, k, t[o].mina, t[o].maxq, t[o].add, t[lc].maxq, t[o].val);
	if (L == R) return t[o].mina + std::max(k, t[o].maxq - ddl[L]) <= m ? L : 0;
	int M = (L + R) >> 1;
	pushdown(o, L, R);
	if (k <= t[lc].maxq) {
		if (t[o].val <= m) return qans(rc, M + 1, R, t[lc].maxq);
		else return qans(lc, L, M, k);
	} else return std::max(qans2(lc, L, M, k), qans(rc, M + 1, R, k));
}

inline void dfs(int x, int fa = 0) {
//	dbg("************ Begin: add: now = %d, fa = %d\n", x, fa);
	if (fa) qadd(1, 1, n, fa - 1, n, p[x] - p[fa]), ddl[fa - 1] += p[x] - p[fa];
//	qadd(1, 1, n, 1, x - 1, -INF);
//	dbg("************ Begin: qans: now = %d\n", x);
	qadd(1, 1, n, 1, x - 1, -INF);
	ans[x] = qans(1, 1, n, -INF);
	qadd(1, 1, n, 1, x - 1, INF);
//	dbg("************ End: now = %d\n", x);
//	qadd(1, 1, n, 1, x - 1, INF);
	for fec(i, x, y) dfs(y, x);
//	dbg("************ Begin: del: now = %d\n", x);
	if (fa) qadd(1, 1, n, fa - 1, n, p[fa] - p[x]), ddl[fa - 1] += p[fa] - p[x];
//	dbg("************ End: del: now = %d\n", x);
}

inline void work() {
//	dbg("p:\n");
	for (int i = 2; i <= n; ++i) p[i] = p[i - 1] + a[i - 1] - d[i - 1];//, dbg("%d%c", p[i], " \n"[i == n]);
//	dbg("q:\n");
	for (int i = 2; i <= n; ++i) q[i] = q[i - 1] + a[i] - d[i - 1];//, dbg("%d%c", q[i], " \n"[i == n]);
	for (int i = n; i; --i) {
		while (tl && p[i] <= p[qq[tl]]) --tl;
		nxt[i] = qq[tl], qq[++tl] = i, addedge(nxt[i], i);
//		dbg("nxt[%d] = %d\n", i, nxt[i]);
	}
	build(1, 1, n);
	for (int i = 1; i <= n; ++i) if (!nxt[i]) dfs(i);
	int tans = 0;
	for (int i = 1; i <= n; ++i) smax(tans, ans[i] - i + 1);//, dbg("ans[%d] = %d\n", i, ans[i]);
	printf("%d\n", tans);
}

inline void init() {
	read(n), read(m);
	for (int i = 1; i < n; ++i) read(d[i]);
	for (int i = 1; i <= n; ++i) read(a[i]);
}

int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#else
	File(traverse);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}
posted @ 2019-09-18 15:54  hankeke303  阅读(311)  评论(1编辑  收藏  举报