1 条题解
-
0
自动搬运
来自洛谷,原作者为

unputdownable
下雨不是任何人的错。搬运于
2025-08-24 22:27:56,当前版本为作者最后更新于2023-01-20 14:14:43,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先考虑如何区分两个人(假设只有两个人)。
不难发现对于任意两个人 ,如果他们参加的表演集合不同(即至少有一天 上场了但是 没上场,或者 上场了但是 没上场),就可以区分 。
这启发我们可以维护若干个集合,每个集合中的人参加的表演集合相同。
如果一个集合大小为 ,此时我们就能认出这个人(你可以同时对照片和姓名维护上文所述集合,你发现这个时候只有一张照片能与这个姓名在表演集合上匹配,然后你就能认出他,但是维护的时候显然不需要维护两个,仅供理解)。
接下来考虑如何维护上文所述集合。
首先,你无需维护参加的表演集合,因为我们只需要知道有哪些(人的)集合,而不需知道他们参加过那些表演。
这样初始时所有人都在集合 中。
每进行一场表演,就相当于更改一些人的表演集合,此时有些集合会分裂,注意到分裂的时候只会分裂参加这场表演的人。
于是对于每场表演,在参演人员中找到在同一个集合里的,直接分裂成一个新集合,考虑到此时只有原集合以及新集合的大小可能为 ,暴力检查就行。
注意到分裂出一个新集合至少需要一个人参加表演,所以集合数目至多为 。
这样就可以把一场表演的复杂度降到 ,带 是因为找相同集合的人的时候用了 实现。
具体细节可以看代码。
Code:
int n,m,k; int tag[100005],xorsum[200005],num[200005],cnttag; // tag 表示这个人在哪个集合 // xorsum 是一个集合里所有人编号的异或和,用于在集合大小为 1 的时候找到这个人。 int Ans[100005]; pii tmp[100005]; int cnt; int checklist[100005],cntchecklist; signed main() { n=read(); m=read(); tmp[0]=make_pair(-1,-1); for(int i=1; i<=n; ++i) xorsum[0]^=i; num[0]=n; for(int T=1; T<=m; ++T) { k=read(); cnt=0; cntchecklist=0; for(int i=1,x; i<=k; ++i) { x=read(); if(!Ans[x]) tmp[++cnt]=make_pair(tag[x],x); } sort(tmp+1,tmp+cnt+1); for(int i=1; i<=cnt; ++i) { if(tmp[i].first!=tmp[i-1].first) { tag[tmp[i].second]=++cnttag; checklist[++cntchecklist]=tmp[i].first; checklist[++cntchecklist]=cnttag; } else tag[tmp[i].second]=cnttag; --num[tmp[i].first]; xorsum[tmp[i].first]^=tmp[i].second; ++num[cnttag]; xorsum[cnttag]^=tmp[i].second; } for(int i=1; i<=cntchecklist; ++i) if(num[checklist[i]]==1) Ans[xorsum[checklist[i]]]=T; } for(int i=1; i<=n; ++i) write(Ans[i]),putchar(" \n"[i==n]); return 0; }
- 1
信息
- ID
- 6383
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者