传送门:http://codeforces.com/problemset/problem/420/B
题目大意:有n个人m个登入/登出,如果一个人在其他所有人登入期间都是登入状态,那么这个人就是领导,给出一部分的记录,问有那些人可能是领导。
思路:change数组记录登入/登出,登入记为1,登出记为-1,talking记录change的前缀和即为此时登入状态的人数,如果某个时刻有人登出,talking记录的是他登出后的情况,把没有登入但是先出现登出的人在change[0]记录登入,有登入没登出的人在change[m+1]记录登出。因为每个时刻只有一个人登入/登出,所以在m个操作中出现的人的登入的区间只有包含,相交,不想交的关系,不存在相等的关系,所以最多只有一个人可以当领导。
代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll M=1e5+10;
ll n,m;
bool leader[M];
ll vis[M];
typedef pair<char,ll> P;
ll id[M];
ll talking[M],change[M];
int main(){
scanf("%lld%lld",&n,&m);
fill(leader+1,leader+1+n,1);
for(ll i=1;i<=m;i++){
char o;
ll num;
cin>>o>>num;
id[i]=num;
if(o=='-' && vis[num]==0)
change[0]++,change[i]--;
else if(o=='-')
change[i]--,vis[num]=0;
else
change[i]++,vis[num]=i;
}
for(ll i=1;i<=n;i++)
if(vis[i])
change[m+1]--;
talking[0]=change[0];
for(ll i=0;i<=m+1;i++)
talking[i]=talking[i-1]+change[i];
ll _id=0;
bool ok=1;
for(ll i=1;i<=m;i++){
if(talking[i]>1 || (change[i]==-1 && talking[i]>0)){//登入的人数大于1时,在这个位子操作的人一定不是领导,在这个位置登出时特殊处理
leader[id[i]]=0;
}
else{
if(!_id)
_id=id[i];
else if(_id!=id[i]){//出现过的id只有一个能当领导,如果出现不相交的情况,会变成有两个人能当领导,如+1,-1,+2,-2,就说明出现过的人没人能当领导
ok=0;
break;
}
}
}
if(!ok){
for(ll i=1;i<=m;i++)
leader[id[i]]=0;
}
ll ans=0;
for(ll i=1;i<=n;i++)
ans+=(leader[i]);
printf("%lld\n",ans);
for(ll i=1;i<=n;i++)
if(leader[i])
printf("%lld ",i);
return 0;
}