题意:给你一个不完整的出入会议的记录,让你判断谁可能是领导,领导必须在其他人在场的时候都在场。
思路:可以将现有的记录转换为若干个区间,如果这个区间被其他区间包含,则这个区间所代表的人不是领导。
当然,记录不完整,有的只有出去的记录,这就需要补上他进来的,我这里默认补在0时间,当然也有只进没出的,默认把他的出时间定在m+1时刻。由于树状数组是从1开始,所以维护时将他们的出入时间默认加1就可以了。
有些人的出入记录没有涉及,那么这些人都可能是领导。对于有记录的人,这些人中只可能有1个领导,如果他们的进出区间有满足领导性质的区间数超过1时(后面有其他区间使得这个人不是领导的那个人的区间也算,只看单个区间),那么这些有记录的人则都不可能是领导。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
using namespace std;
struct node
{
int l,r,num;
};
int n,m,mm;
vector<node>v;
vector<int>ren;
int p[111111];
bool vis[111111];
bool ans[111111];
char s[3];
int a;
int c[111111];
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int y)
{
for(int i=x;i<=mm;i+=lowbit(i))
{
c[i]+=y;
}
}
int sum(int x)
{
int ss=0;
for(int i=x;i>0;i-=lowbit(i))ss+=c[i];
return ss;
}
int main()
{
scanf("%d%d",&n,&m);
mm=m+2;
memset(p,0,sizeof(p));
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++)
{
scanf("%s%d",s,&a);
if(s[0]=='+')p[a]=i;
else
{
v.push_back((node){p[a]+1,i+1,a});
p[a]=0;
}
ren.push_back(a);
}
ren.erase(unique(ren.begin(),ren.end()),ren.end());
int rsize=ren.size();
int nnn=0;
for(int i=1;i<=n;i++)
{
if(p[i])
{
v.push_back((node){p[i]+1,m+2,i});
}
}
int size=v.size();
for(int i=0;i<size;i++)
{
add(v[i].l,1);
add(v[i].r,-1);
//cout<<v[i].l<<" "<<v[i].r<<" "<<v[i].num<<endl;
}
memset(ans,0,sizeof(ans));
for(int i=0;i<size;i++)
{
if(sum(v[i].r)!=0||(v[i].l!=1&&sum(v[i].l)!=1))
{
ans[v[i].num]=1;
//cout<<v[i].num<<" "<<sum(v[i].r)<<" "<<sum(v[i].l)<<"!!"<<endl;
}
else if(!vis[v[i].num])
{
vis[v[i].num]=1;
nnn++;
}
}
if(nnn>1)
{
//cout<<1<<endl;
for(int i=0;i<rsize;i++)
{
ans[ren[i]]=1;
//cout<<ren[i]<<endl;
}
}
int cnt=0;
for(int i=1;i<=n;i++)
{
if(!ans[i])cnt++;
}
cout<<cnt<<endl;
for(int i=1;i<=n;i++)
{
if(!ans[i])printf("%d ",i);
}
cout<<endl;
return 0;
}