[题解] [JSOI2014] 歌剧表演

题面

题解

我们可以把这些人拆成一些集合, 保证对于一个集合你只知道这个整体, 而无法分辨出哪一部分是哪些人

起初所有人都在一个集合中

我们对于每一次操作, 肯定会有一些人属于同一个集合

那你就可以从这个集合中分辨出这些人来, 把这些人抠出来重新丢进一个集合

最后一个人一个集合的就可以被分辨出来

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
const int N = 100005; 
using namespace std;

int n, m, id[N], a[N], ans[N], cnt = 1;
set<int> s[N]; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w; 
}

bool cmp(int a, int b) { return id[a] < id[b]; }

int main()
{
    n = read <int> (), m = read <int> ();
    for(int i = 1; i <= n; i++) s[id[i] = 1].insert(i); 
    int num, last; 
    for(int t = 1; t <= m; t++)
    {
	num = read <int> ();
	for(int i = 1; i <= num; i++) a[i] = read <int> ();
	sort(a + 1, a + num + 1, cmp), a[num + 1] = 0;
	last = 1;
	for(int i = 2; i <= num + 1; i++)
	    if(id[a[i]] != id[a[i - 1]])
	    {
		for(int j = last; j < i; j++) s[id[a[j]]].erase(a[j]);
		++cnt; 
		if(s[id[a[last]]].size() == 1 && !ans[*s[id[a[last]]].begin()])
		    ans[*s[id[a[last]]].begin()] = t; 
		if(last == i - 1 && !ans[a[last]])
		    ans[a[last]] = t;
		for(int j = last; j < i; j++) s[id[a[j]] = cnt].insert(a[j]);
		last = i; 
	    }
    }
    for(int i = 1; i <= n; i++) printf("%d%c", ans[i], i == n ? '\n' : ' '); 
    return 0; 
}
posted @ 2020-02-11 20:45  ztlztl  阅读(89)  评论(0编辑  收藏  举报