题解:P12082 [Ynoi1998] Frühlingsbeginn

我们可以先把半开区间 \([l, r)\) 变成闭区间 \([l, r-1]\),坐标范围相应变成 \([1, n-1]\)。把操作离线下来,每个插入的区间就变成了一个带存在时间范围 \([s, e]\) 的静态区间。如果一直没被删,结束时间就是 \(m\)。

遇到询问 \((l, r, t)\) 时,显然只要把时刻 \(t\) 存在且完全被 \([l, r]\) 包含的区间全都拿出来求并集就行了。因为能用的区间只有这些,全选肯定是最优的,如果全选都盖不住 \([l, r]\),那任何子集也肯定盖不住。所以原问题直接等价于判断这些区间的并集是不是刚好等于 \([l, r]\)。

面对多组询问,单纯按时间或者端点排序都不太好搞包含关系,比较自然的想法是上猫树分治。在分治区间 \([L, R]\) 以及中点 \(\text{mid}\) 上,把每个询问挂在它第一次跨过 \(\text{mid}\) 的节点。操作区间同理,跨过 \(\text{mid}\) 的留在当前节点,否则丢到左右儿子去递归。这样做每个询问只会在一个节点被处理一次,每个操作区间最多下放 \(O(\log n)\) 次。

留在当前节点的询问都满足 \(l \le \text{mid} < r\)。对这些询问有用的区间分成三种:跨过 \(\text{mid}\) 的、全在左边的、全在右边的。我们先看跨过 \(\text{mid}\) 的部分。这些区间都包含 \(\text{mid}\) 和 \(\text{mid}+1\),所以只要把完全包含在询问里的有效区间拿出来,并集绝对是连续的一段 \([f, g]\)。如果根本没有符合要求的区间,就设 \(f=\text{mid}+1, g=\text{mid}\)。不然的话 \(f\) 就是这些区间里左端点的最小值,\(g\) 就是右端点的最大值。查的时候只考虑被询问包含且时刻 \(t\) 存活的区间。

为了快速求 \(f\) 和 \(g\),对于同一位置 \(x\) 开头的区间,想往左扩肯定找右端点尽量小的,所以维护 \(A_x = \min \{ r_i \mid l_i=x \}\),这里限制区间跨过 \(\text{mid}\) 且当前时间有效。找不到就设正无穷。那询问的 \(f\) 其实就是满足 \(A_x \le r\) 的最小的 \(x \in [l, \text{mid}]\)。右端点对称着来,维护 \(B_x = \max \{ l_i \mid r_i=x \}\),找不到设负无穷,那 \(g\) 就是满足 \(B_x \ge l\) 的最大的 \(x \in [\text{mid}+1, r]\)。因为有时间限制,直接把区间按存活时间做成加减事件,连同询问一起按时间跑扫描线。用两棵线段树分别维护 \(A_x\) 和 \(B_x\) 的最值,查 \(f\) 和 \(g\) 只要在线段树上二分就行了。

然后再处理两侧的区间,比如左侧。因为中间部分已经覆盖了 \([f, g]\),左边剩下的任务就是看看能不能从 \(l\) 一路连上 \(f-1\)。我们设 \(h\) 是从 \(l\) 开始向右连续覆盖到的第一个没被盖住的位置,一开始 \(h=l\)。把询问和左侧区间都按左端点从小到大扫。扫到某个询问的左端点时,把它丢进一棵以询问时间为下标的线段树里,初值设为 \(l\)。扫到区间 \([a, b]\) 时,它能且只能帮到询问时间在它存活时间 \([s, e]\) 内的询问,也就是给这些询问执行 \(h \gets \max(h, b+1)\)。线段树上直接做区间 chmax 即可。

这里有个需要注意的细节,如果扫到了某个左端点 \(x\),但线段树里某些询问的 \(h < x\),说明它们在 \(h\) 这里断档了,并且后面将要扫的区间左端点都 \(\ge x > h\),没救了。这时候直接把这些询问弹出来,它们的左侧延伸极限就是当前的 \(h\)。所以每次把左端点为 \(x\) 的询问加进线段树、并处理完左端点为 \(x\) 的所有区间后,要把线段树里仍满足 \(h=x\) 的询问(通过维护全局最小值)连带询问编号一起提出来处理掉。扫完之后还没被弹出的询问,说明它们能顺畅地一路盖到中点,极限设为 \(\text{mid}+1\)。这样左侧能接上中间的条件就是 \(h \ge f\)。

右侧操作完全是对称的,设 \(k\) 为从 \(r\) 往左走最后一个没被盖住的位置,初值 \(k=r\)。按右端点从大到小扫,遇到区间就执行区间 chmin 也就是 \(k \gets \min(k, a-1)\)。遇到 \(k > x\) 就提前弹出断档的询问,扫完后剩下的询问对应的 \(k\) 设为 \(\text{mid}\)。右侧接上的条件自然就是 \(k \le g\)。

综上,判断每个询问是否合法,只要看 \(h \ge f\) 且 \(k \le g\) 是否同时成立就行了。

时间复杂度 \(O(n + m \log n \log m)\),空间复杂度 \(O(n + m \log n)\)。

#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int INF = 1e9;
namespace FastIO {
	const int BUFSIZE = 1 << 20;
	char ibuf[BUFSIZE];
	int ipos = 0, ilen = 0;
	inline char gc() {
		if (ipos == ilen) {
			ilen = fread(ibuf, 1, BUFSIZE, stdin);
			ipos = 0;
			if (ilen == 0) {
				return EOF;
			}
		}
		return ibuf[ipos++];
	}
	template<typename T>
	inline void read(T &x) {
		x = 0;
		int f = 1;
		char c = gc();
		while (c != '-' && (c < '0' || c > '9')) {
			c = gc();
		}
		if (c == '-') {
			f = -1;
			c = gc();
		}
		while (c >= '0' && c <= '9') {
			x = x * 10 + (c - '0');
			c = gc();
		}
		x *= f;
	}

}
struct operation {
	int l, r, ll, rr, nxt;
} op[500005];
struct Node {
	int l, r, x, nxt;
} que[500005];
struct N {
	int id, v;
} edge[11000005];
struct N1 {
	int x, op, id, nxt;
} evnt[1000005];
const int MAXN = 1000005;
int n, m, headm[4000005], headq[4000005], headl[4000005], headr[4000005], coverl[500005], coverr[500005], arrivel[500005], arriver[500005], qtmp[500005], rk[500005], tim[500005], bit[500005], edgeid, bq[MAXN], bo[MAXN], bmark[MAXN], qnext[500005], onext[500005], bstamp, heade[4000005], taile[4000005], opnode[500005], eventid;
char hashq[4000005];
bool ans[500005];
namespace Heap {
	struct HeapNode { 
		int l, r, d; 
	} hl[500005], hr[500005];
	int rootl[1000005], rootr[1000005];
	bool active[500005];
	int mergeL(int x, int y) {
		if (!x || !y) {
			return x | y;
		}
		if (op[x].r > op[y].r || (op[x].r == op[y].r && x > y)) {
			swap(x, y);
		}
		hl[x].r = mergeL(hl[x].r, y);
		if (hl[hl[x].l].d < hl[hl[x].r].d) {
			swap(hl[x].l, hl[x].r);
		}
		hl[x].d = hl[hl[x].r].d + 1;
		return x;
	}
	int mergeR(int x, int y) {
		if (!x || !y) {
			return x | y;
		}
		if (op[x].l < op[y].l || (op[x].l == op[y].l && x < y)) {
			swap(x, y);
		}
		hr[x].r = mergeR(hr[x].r, y);
		if (hr[hr[x].l].d < hr[hr[x].r].d) {
			swap(hr[x].l, hr[x].r);
		}
		hr[x].d = hr[hr[x].r].d + 1;
		return x;
	}
	int getmin(int x) {
		while (rootl[x] && !active[rootl[x]]) {
			int id = rootl[x];
			rootl[x] = mergeL(hl[id].l, hl[id].r);
		}
		return rootl[x] ? op[rootl[x]].r : INF;
	}
	int getmax(int x) {
		while (rootr[x] && !active[rootr[x]]) {
			int id = rootr[x];
			rootr[x] = mergeR(hr[id].l, hr[id].r);
		}
		return rootr[x] ? op[rootr[x]].l : 0;
	}
};
int visl[1000005], visr[1000005], listl[500005], listr[500005], stamp, cntl, cntr;
void addedge(int &numid, int id) {
	edge[++edgeid] = {id, numid};
	numid = edgeid;
}
void addevent(int p, int x, int typ, int id) {
	evnt[++eventid] = {x, typ, id, 0};
	if (taile[p]) {
		evnt[taile[p]].nxt = eventid;
	} else {
		heade[p] = eventid;
	}
	taile[p] = eventid;
}
void getop(int id) {
	int p = 1, l = 1, r = n;
	while (true) {
		if (l == r) {
			op[id].nxt = headm[p];
			headm[p] = id;
			opnode[id] = p;
			addevent(p, op[id].ll, 1, id);
			return;
		}
		int mid = (l + r) >> 1;
		if (op[id].l <= mid && mid < op[id].r) {
			op[id].nxt = headm[p];
			headm[p] = id;
			opnode[id] = p;
			addevent(p, op[id].ll, 1, id);
			return;
		}
		if (op[id].r <= mid) {
			addedge(headl[p], id);
			r = mid;
			p *= 2;
		} else {
			addedge(headr[p], id);
			l = mid + 1;
			p = p * 2 + 1;
		}
	}
}
void getque(int id) {
	int p = 1, l = 1, r = n;
	while (true) {
		hashq[p] = 1;
		if (l == r) {
			que[id].nxt = headq[p];
			headq[p] = id;
			addevent(p, que[id].x, 0, id);
			return;
		}
		int mid = (l + r) >> 1;
		if (que[id].l <= mid && mid < que[id].r) {
			que[id].nxt = headq[p];
			headq[p] = id;
			addevent(p, que[id].x, 0, id);
			return;
		}
		if (que[id].r <= mid) {
			r = mid;
			p *= 2;
		} else {
			l = mid + 1;
			p = p * 2 + 1;
		}
	}
}
namespace LTree {
	int minn[4000005];
	void buildtree(int p, int l, int r) {
		minn[p] = INF;
		if (l == r) {
			return;
		}
		int mid = (l + r) >> 1;
		buildtree(p * 2, l, mid);
		buildtree(p * 2 + 1, mid + 1, r);
	}
	void change(int p, int l, int r, int x, int d) {
		if (l == r) {
			minn[p] = d;
			return;
		}
		int mid = (l + r) >> 1;
		if (x <= mid) {
			change(p * 2, l, mid, x, d);
		} else {
			change(p * 2 + 1, mid + 1, r, x, d);
		}
		minn[p] = min(minn[p * 2], minn[p * 2 + 1]);
	}
	int get(int p, int l, int r, int ll, int rr, int d) {
		if (r < ll || l > rr || minn[p] > d) {
			return -1;
		}
		if (l == r) {
			return l;
		}
		int mid = (l + r) >> 1, pos = get(p * 2, l, mid, ll, rr, d);
		if (pos != -1) {
			return pos;
		}
		return get(p * 2 + 1, mid + 1, r, ll, rr, d);
	}
};
namespace RTree {
	int maxn[4000005];
	void buildtree(int p, int l, int r) {
		maxn[p] = 0;
		if (l == r) {
			return;
		}
		int mid = (l + r) >> 1;
		buildtree(p * 2, l, mid);
		buildtree(p * 2 + 1, mid + 1, r);
	} 
	void change(int p, int l, int r, int x, int d) {
		if (l == r) {
			maxn[p] = d;
			return;
		}
		int mid = (l + r) >> 1;
		if (x <= mid) {
			change(p * 2, l, mid, x, d);
		} else {
			change(p * 2 + 1, mid + 1, r, x, d);
		}
		maxn[p] = max(maxn[p * 2], maxn[p * 2 + 1]);
	}
	int get(int p, int l, int r, int ll, int rr, int x) {
		if (r < ll || l > rr || maxn[p] < x) {
			return -1;
		}
		if (l == r) {
			return l;
		}
		int mid = (l + r) >> 1, pos = get(p * 2 + 1, mid + 1, r, ll, rr, x);
		if (pos != -1) {
			return pos;
		}
		return get(p * 2, l, mid, ll, rr, x);
	}
};
namespace L {
	pair<int, int> minn[2000005];
	int tag[2000005];
	void buildtree(int p, int l, int r) {
		minn[p] = {INF, 0};
		tag[p] = 0;
		if (l == r) {
			return;
		}
		int mid = (l + r) >> 1;
		buildtree(p * 2, l, mid);
		buildtree(p * 2 + 1, mid + 1, r);
	}
	void pushdown(int p) {
		if (tag[p]) {
			if (minn[p * 2].first != INF) {
				minn[p * 2].first = max(minn[p * 2].first, tag[p]);
				tag[p * 2] = max(tag[p * 2], tag[p]);
			}
			if (minn[p * 2 + 1].first != INF) {
				minn[p * 2 + 1].first = max(minn[p * 2 + 1].first, tag[p]);
				tag[p * 2 + 1] = max(tag[p * 2 + 1], tag[p]);
			}
			tag[p] = 0;
		}
	}
	void change(int p, int l, int r, int ll, int rr, int x) {
		if (ll > rr || minn[p].first >= x) {
			return;
		}
		if (ll <= l && r <= rr) {
			minn[p].first = max(minn[p].first, x);
			tag[p] = max(tag[p], x);
			return;
		}
		pushdown(p);
		int mid = (l + r) >> 1;
		if (ll <= mid) {
			change(p * 2, l, mid, ll, rr, x);
		}
		if (rr > mid) {
			change(p * 2 + 1, mid + 1, r, ll, rr, x);
		}
		minn[p] = min(minn[p * 2], minn[p * 2 + 1]);
	}
	void update(int p, int l, int r, int x, pair<int, int> d) {
		if (l == r) {
			minn[p] = d;
			tag[p] = 0;
			return;
		}
		pushdown(p);
		int mid = (l + r) >> 1;
		if (x <= mid) {
			update(p * 2, l, mid, x, d);
		} else {
			update(p * 2 + 1, mid + 1, r, x, d);
		}
		minn[p] = min(minn[p * 2], minn[p * 2 + 1]);
	}
	void erase(int p, int l, int r, int x) {
		if (minn[p].first != x) {
			return;
		}
		if (l == r) {
			arrivel[minn[p].second] = x;
			minn[p] = {INF, 0};
			tag[p] = 0;
			return;
		}
		pushdown(p);
		int mid = (l + r) >> 1;
		if (minn[p * 2].first == x) {
			erase(p * 2, l, mid, x);
		}
		if (minn[p * 2 + 1].first == x) {
			erase(p * 2 + 1, mid + 1, r, x);
		}
		minn[p] = min(minn[p * 2], minn[p * 2 + 1]);
	}
};
namespace R {
	pair<int, int> maxn[2000005];
	int tag[2000005];
	void buildtree(int p, int l, int r) {
		maxn[p] = {-INF, 0};
		tag[p] = INF;
		if (l == r) {
			return;
		}
		int mid = (l + r) >> 1;
		buildtree(p * 2, l, mid);
		buildtree(p * 2 + 1, mid + 1, r);
	}
	void pushdown(int p) {
		if (tag[p] != INF) {
			if (maxn[p * 2].first != -INF) {
				maxn[p * 2].first = min(maxn[p * 2].first, tag[p]);
				tag[p * 2] = min(tag[p * 2], tag[p]);
			}
			if (maxn[p * 2 + 1].first != -INF) {
				maxn[p * 2 + 1].first = min(maxn[p * 2 + 1].first, tag[p]);
				tag[p * 2 + 1] = min(tag[p * 2 + 1], tag[p]);
			}
			tag[p] = INF;
		}
	}
	void change(int p, int l, int r, int ll, int rr, int x) {
		if (ll > rr || maxn[p].first <= x) {
			return;
		}
		if (ll <= l && r <= rr) {
			maxn[p].first = min(maxn[p].first, x);
			tag[p] = min(tag[p], x);
			return;
		}
		pushdown(p);
		int mid = (l + r) >> 1;
		if (ll <= mid) {
			change(p * 2, l, mid, ll, rr, x);
		}
		if (rr > mid) {
			change(p * 2 + 1, mid + 1, r, ll, rr, x);
		}
		maxn[p] = max(maxn[p * 2], maxn[p * 2 + 1]);
	}
	void update(int p, int l, int r, int x, pair<int, int> d) {
		if (l == r) {
			maxn[p] = d;
			tag[p] = INF;
			return;
		}
		pushdown(p);
		int mid = (l + r) >> 1;
		if (x <= mid) {
			update(p * 2, l, mid, x, d);
		} else {
			update(p * 2 + 1, mid + 1, r, x, d);
		}
		maxn[p] = max(maxn[p * 2], maxn[p * 2 + 1]);
	}
	void erase(int p, int l, int r, int x) {
		if (maxn[p].first != x) {
			return;
		}
		if (l == r) {
			arriver[maxn[p].second] = x;
			maxn[p] = {-INF, 0};
			tag[p] = INF;
			return;
		}
		pushdown(p);
		int mid = (l + r) >> 1;
		if (maxn[p * 2].first == x) {
			erase(p * 2, l, mid, x);
		}
		if (maxn[p * 2 + 1].first == x) {
			erase(p * 2 + 1, mid + 1, r, x);
		}
		maxn[p] = max(maxn[p * 2], maxn[p * 2 + 1]);
	}
};
void setl(int x, int v) {
	if (visl[x] != stamp) {
		visl[x] = stamp;
		listl[++cntl] = x;
	}
	LTree::change(1, 1, n, x, v);
}
void setr(int x, int v) {
	if (visr[x] != stamp) {
		visr[x] = stamp;
		listr[++cntr] = x;
	}
	RTree::change(1, 1, n, x, v);
}
int lowbit(int x) {
	return x & (-x);
}
void change(int x, int y) {
	for (; x <= m; x += lowbit(x)) {
		bit[x] += y;
	}
}
int getsum(int x) {
	int res = 0;
	for (; x; x -= lowbit(x)) {
		res += bit[x];
	}
	return res;
}
void worklf(int p) {
	for (int i = headm[p]; i; i = op[i].nxt) {
		change(op[i].ll, 1);
		change(op[i].rr + 1, -1);
	}
	for (int i = headq[p]; i; i = que[i].nxt) {
		ans[i] = (getsum(que[i].x) > 0);
	}
	for (int i = headm[p]; i; i = op[i].nxt) {
		change(op[i].ll, -1);
		change(op[i].rr + 1, 1);
	}
}
void solve(int p, int l, int r) {
	if (!hashq[p]) {
		return;
	}
	if (l == r) {
		worklf(p);
		return;
	}
	int mid = (l + r) >> 1, len = 0, siz = 0;
	for (int i = headq[p]; i; i = que[i].nxt) {
		qtmp[++len] = i;
	}
	if (len) {
		reverse(qtmp + 1, qtmp + len + 1);
		for (int i = 1; i <= len; i = -~i) {
			tim[i] = que[qtmp[i]].x;
			rk[qtmp[i]] = i;
			arrivel[qtmp[i]] = mid + 1;
			arriver[qtmp[i]] = mid;
		}
		stamp ++;
		cntl = cntr = 0;
		for (int i = heade[p]; i; i = evnt[i].nxt) {
			int id = evnt[i].id;
			if (evnt[i].op == 1) {
				int oldl = Heap::getmin(op[id].l), oldr = Heap::getmax(op[id].r);
				Heap::active[id] = 1;
				Heap::rootl[op[id].l] = Heap::mergeL(Heap::rootl[op[id].l], id);
				Heap::rootr[op[id].r] = Heap::mergeR(Heap::rootr[op[id].r], id);
				if (op[id].r < oldl) {
					setl(op[id].l, op[id].r);
				}
				if (op[id].l > oldr) {
					setr(op[id].r, op[id].l);
				}
			} else if (evnt[i].op == -1) {
				int oldl = Heap::getmin(op[id].l), oldr = Heap::getmax(op[id].r);
				Heap::active[id] = 0;
				int newl = Heap::getmin(op[id].l), newr = Heap::getmax(op[id].r);
				if (oldl == op[id].r) {
					setl(op[id].l, newl);
				}
				if (oldr == op[id].l) {
					setr(op[id].r, newr);
				}
			} else {
				coverl[id] = LTree::get(1, 1, n, que[id].l, mid, que[id].r);
				coverr[id] = RTree::get(1, 1, n, mid + 1, que[id].r, que[id].l);
				if (coverl[id] == -1) {
					coverl[id] = mid + 1;
				}
				if (coverr[id] == -1) {
					coverr[id] = mid;
				}
			}
		}
		for (int i = 1; i <= cntl; i = -~i) {
			LTree::change(1, 1, n, listl[i], INF);
		}
		for (int i = 1; i <= cntr; i = -~i) {
			RTree::change(1, 1, n, listr[i], 0);
		}
		bstamp = -~bstamp ;
		for (int k = 1; k <= len; k = -~k) {
			int id = qtmp[k], x = que[id].l;
			if (bmark[x] != bstamp) {
				bmark[x] = bstamp;
				bq[x] = bo[x] = 0;
			}
			qnext[id] = bq[x];
			bq[x] = id;
		}
		for (int k = headl[p]; k; k = edge[k].v) {
			int id = edge[k].id, x = op[id].l;
			if (bmark[x] != bstamp) {
				bmark[x] = bstamp;
				bq[x] = bo[x] = 0;
			}
			onext[id] = bo[x];
			bo[x] = id;
		}
		L::buildtree(1, 1, len);
		for (int x = l; x <= mid; x ++) {
			if (bmark[x] == bstamp) {
				for (int id = bq[x]; id; id = qnext[id]) {
					L::update(1, 1, len, rk[id], {x, id});
				}
				for (int id = bo[x]; id; id = onext[id]) {
					L::change(1, 1, len, lower_bound(tim + 1, tim + 1 + len, op[id].ll) - tim, upper_bound(tim + 1, tim + 1 + len, op[id].rr) - tim - 1, op[id].r + 1);
				}
			}
			if (L::minn[1].first == x) {
				L::erase(1, 1, len, x);
			}
		}
		bstamp = -~bstamp;
		for (int k = 1; k <= len; k = -~k) {
			int id = qtmp[k], x = que[id].r;
			if (bmark[x] != bstamp) {
				bmark[x] = bstamp;
				bq[x] = bo[x] = 0;
			}
			qnext[id] = bq[x];
			bq[x] = id;
		}
		for (int k = headr[p]; k; k = edge[k].v) {
			int id = edge[k].id, x = op[id].r;
			if (bmark[x] != bstamp) {
				bmark[x] = bstamp;
				bq[x] = bo[x] = 0;
			}
			onext[id] = bo[x];
			bo[x] = id;
		}
		R::buildtree(1, 1, len);
		for (int x = r; x > mid; x --) {
			if (bmark[x] == bstamp) {
				for (int id = bq[x]; id; id = qnext[id]) {
					R::update(1, 1, len, rk[id], {x, id});
				}
				for (int id = bo[x]; id; id = onext[id]) {
					R::change(1, 1, len, lower_bound(tim + 1, tim + 1 + len, op[id].ll) - tim, upper_bound(tim + 1, tim + 1 + len, op[id].rr) - tim - 1, op[id].l - 1);
				}
			}
			if (R::maxn[1].first == x) {
				R::erase(1, 1, len, x);
			}
		}
		for (int k = 1; k <= len; k = -~k) {
			int id = qtmp[k];
			ans[id] = (arrivel[id] >= coverl[id] && arriver[id] <= coverr[id]);
		}
	}
	if (hashq[p * 2]) {
		solve(p * 2, l, mid);
	}
	if (hashq[p * 2 + 1]) {
		solve(p * 2 + 1, mid + 1, r);
	}
}
signed main() {
	int cnt = 0;
	FastIO::read(n);
	FastIO::read(m);
	n --;
	for (int i = 1; i <= m; i = -~i) {
		int opt, x, y;
		FastIO::read(opt);
		FastIO::read(x);
		if (opt == 1) {
			FastIO::read(y);
			op[i] = {x, y - 1, i, m, 0};
			getop(i);
		} else if (opt == 2) {
			op[x].rr = i - 1;
			addevent(opnode[x], i, -1, x);
		} else {
			FastIO::read(y);
			que[++cnt] = {x, y - 1, i, 0};
			getque(cnt);
		}
	}
	for (int i = 1; i <= m; i = -~i) {
		if (opnode[i] && op[i].rr == m) {
			addevent(opnode[i], m + 1, -1, i);
		}
	}
	LTree::buildtree(1, 1, n);
	RTree::buildtree(1, 1, n);
	solve(1, 1, n);
	for (int i = 1; i <= cnt; i = -~i) {
		if (ans[i]) {
			puts("Y");
		} else {
			puts("N");
		}
	}
	return 0;
}
posted @ 2026-11-11 15:10  xuyifei0302  阅读(4)  评论(0)    收藏  举报