题目地址:http://codeforces.com/problemset/problem/420/B
题目大意:
公司要开会,有些人会上线,有些人会下线,只有在任何会议都在场的人才能当leader
现在给你一个片段,要你判断有哪些人是有可能当leader的
解题思路:
当你退出或者上线的时候有人还在线的话是肯定不能当leader的
另外就是当你确定下线了,别人又上线的时候,你也是肯定不能当leader的
因为我们一开始不知道到底有多少人已经在线上了,所以要倒着走一遍,看有多少人已经在线上了
然后在正着走来判断。
具体的代码如下:
/*************************************************************************
> File Name: 420B.cpp
> Author: BobLee
> Mail: boblee0717@gmail.com
> Created Time: 2014年04月26日 星期六 18时13分17秒
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
const int maxn = 100000+20;
int n,m;
struct node
{
char o[5];
int id;
};
node op[maxn];
int a[maxn];
int b[maxn];
int del[maxn];
void read()
{
for(int i=1;i<=m;i++)
scanf("%s%d",op[i].o,&op[i].id);
}
void solve()
{
memset(b,1,sizeof(b)); //b 用来判断这个人能不能当leader
memset(a,0,sizeof(a)); //a 用来记录这个人在最开始的是不是在会议上
int tot = 0;
for(int i=m;i>=1;i--) //从尾巴往前遍历,看到退出了,那就说明之前在会议上,然后当遇到之前登陆的时候,就说明在之前不在会议上
{
if(op[i].o[0]=='-')
{
a[op[i].id] = 1;
}
else
a[op[i].id] = 0;
}
//也就是说tot就是用来记录这个片段最开始之前到底有多少人在线上
for(int i=1;i<=n;i++)
{
if(a[i])
tot++;
}
int last = 0;//用来记录在遍历过程中最后一个人是谁
for(int i=1;i<=m;i++)
{
/*
* 这里用了2个变量来判断这个人能不能当leader
* del是用来表示当他退出或者登陆的时候有没有人,有人就是1,没有就是0
* b则是用来表示他是否上线过
*/
if(op[i].o[0]=='-')
{
tot--;
if(tot>0) del[op[i].id] = 1;
last = op[i].id;
/*
* 下面这句话表示如果当你退出的时候不是最后一个片段,并且目前线上没有人了
* 那么你退出代表你就肯定是下线了,那后面的会议你不能参加,那也就是没有可能参会了
*/
if(i!=m && !tot)
b[op[i].id] = 0;
}
else
{
/*
* 这句话的意思是当你登陆的时候有人或者在你登陆之前有别人退出过,那么你就不能当这个leader
*/
if(tot>0 ||(op[i].id != last && last))
del[op[i].id] = 1;
tot++;
b[op[i].id] = 1;
}
}
int ans = 0;
/*
* 能当leader的要求是你不仅在登陆和登出的时候没人,而且还要在线上
*/
for(int i=1;i<=n;i++)
{
if(!del[i] && b[i])
ans++;
}
printf("%d\n",ans);
bool f=false;
for(int i=1;i<=n;i++)
{
if(!del[i] && b[i])
{
if(!f)
{
printf("%d",i);
f=true;
}
else
printf(" %d",i);
}
}
printf("\n");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
read();
solve();
}
return 0;
}