题意:n 个人参加线上会议,某经理记录了中间一段时间的 m 条上下线记录(1 ≤ n, m ≤ 105)。+ 表示上线,- 表示下线。leader是指只要有人在线,他都在线的人。求所有可能的leader。
题目链接:http://codeforces.com/problemset/problem/420/B
——>>这样的一种人,他们在记录中的第一条记录是下线的,定义为xx。。
三个断言:
1)如果xx存在,那么出现的人中,leader只可能是最后出现的那个xx。。
2)如果xx不存在,那么出现的人中,leader只可能是第一个登录的人。。
3)没出现过的人都可以是leader。。
#include <cstdio>
#include <set>
using std::set;
const int MAXN = 100000 + 10;
int n, m;
char op[MAXN];
int p[MAXN];
int sum, leader;
int firstPlus = -1, lastInfinite = -1;
bool vis[MAXN];
void Init()
{
sum = n;
for (int i = 1; i <= n; ++i)
{
vis[i] = true;
}
}
void Read()
{
for (int i = 1; i <= m; ++i)
{
getchar();
scanf("%c%d", op + i, p + i);
if (op[i] == '-' && vis[p[i]] == true)
{
lastInfinite = p[i];
}
if (firstPlus == -1 && op[i] == '+')
{
firstPlus = p[i];
}
if (vis[p[i]])
{
vis[p[i]] = false;
--sum;
}
}
}
void Solve()
{
set<int> se;
leader = lastInfinite == -1 ? firstPlus : lastInfinite;
if (lastInfinite != -1)
{
se.insert(leader);
}
for (int i = 1; i <= m; ++i)
{
if (op[i] == '+')
{
se.insert(p[i]);
if (se.find(leader) == se.end())
{
leader = -1;
break;
}
}
else
{
if (!se.empty())
{
se.erase(p[i]);
}
if (!se.empty() && se.find(leader) == se.end())
{
leader = -1;
break;
}
}
}
if (leader != -1)
{
vis[leader] = true;
++sum;
}
}
void Output()
{
printf("%d\n", sum);
if (sum == 0) return;
bool first = true;
for (int i = 1; i <= n; ++i)
{
if (vis[i])
{
if (first)
{
first = !first;
}
else
{
printf(" ");
}
printf("%d", i);
}
}
puts("");
}
int main()
{
while (scanf("%d%d", &n, &m) == 2)
{
Init();
Read();
Solve();
Output();
}
return 0;
}